Salut,
je desire realiser un client/serveur TCP
le probleme est que les fonctions accept et recv sont bloquante.
donc cela bloque l'affichage etc...
mon probleme est le suivant ,je devellope un jeu en Opengl et GLUT et c++ (pour la portabilité)
GLUT est tres simple d'utilisation est surtout portable:
la creation d'une fenetre la gestion du clavier ,de la souris,etc... est tres simple par rapport a un programme realise en utilisant la MFC.
realiser un jeu en MFC en plein ecran est tres compliqué voir impossible, ne parlons pas de la gestion des evenements.
Opengl c'est genial en quelques lignes de programme comprehensible, on a vite fait de faire de la 2d ou 3d en plein ecran.
la ou j'ai un probleme c'est d'implementer un client/serveur
les fonctions accept et recv sont bloquante,donc bloque l'affichage.
2 possibilités ,soit j'utilise un thread ou WSAAsynSelect(..)
les threads, je n'ai pas trouvé d'exemple claire :
comment on declare un thread, quel sont les fonctions a utiliser, dans quel ordre etc....
WSAasyncSelect(..) utilise un HWND, un HANDLE sur la fenetre, est les message windows.
mais comme j'utilise GLUT, je ne vois pas comment reccuperer le HANDLE sur la fenetre de mon application est encore moins les message windows !
quelqu'un m'a sugerer de faire une fenetre invisible, mais je ne maitrise pas du trop la MFC, pour creer une fenetre.
peut etre y a t-il moyen de reccuperer le HANDLE de la fenetre cree avec GLUT,(car pour moi c'est une surcouche)
bref je ne sais plus vers quoi me diriger.
et les threads j'y connait rien ,je comprend a quoi ça sert ,et je pense que cela resoudrais mon probleme,mais les recherches que j'ai fais sur internet n'ont rien donné,pas d'exemple simple, aucune explication de la mise en place d'un thread. bref le mistere.
mon client/serveur fonctionne cependant.
mais je ne sais pas si ce que j'ai fais et bon au niveau de mes class et des buffers d'entre/sortie des sockets.
quelqu'un peut t-il me conseiller sur la structure de mes class et des buffer ?
quelq'un peut t-il m'aprendre a faire un thread ?
voici ce que j'ai fais :
j'ai cree une class socket (socketReseau)
une class serveur qui derive de socketReseau
une class client qui derive de socketReseau egalement
la class serveur possede une liste dynamique de type generic ici la liste est du type socketReseau, cette liste correspond aux clients qui se connecterons.
le type Liste est une liste generic ,on peut y acceder avec un iterateur ou comme un tableau Liste[0].
pour ce qui est des buffers d'entre sortie des sockets (voir class socketReseau, j'ai prevu 2 buffers un pour l'entree et un pour la sortie.
je ne sais pas encore ce qui est le mieux au niveau des buffers ,ais je fais le bon choix ?
peut etre q'un seul buffer suffirais ,et pourrais etre sur un void* !!?
chaque buffer a une taille de 1024 (voir constante)
voici ce que fais mon serveur:
initialiser winsock
demarrer serveur
ecouter
accept (bloque !, il attend une connexion d'un client, donc pas cool !)
si client accepte,
le serveur attend le nom du client
recv (bloque aussi !)
le serveur envoie son nom au client
send
voici ce que fais mon client:
initialiser winsock
connecter
le client envoie son nom au serveur
send
le client attend le nom du serveur
recv (bloque !)
je vous passe les detaille de la saisie au clavier du port de l'adresse ip du serveur, du nom du client et du nom du serveur !
BREF :
mon client se connecte correctement a mon serveur
ils echangent leurs nom ,et je fais afficher l'adresse ip de chacun a l'ecran
pour l'instant le serveur ne gere q'un seul client (voir constructeur de la class serveur.(la liste n'a q'un socket)
voici mon MAIN :
int main(int argc, char** argv)
{
int idFenetre; // Identifiant de la fenêtre principale
/*** Initialisations ***/
glutInit(&argc, argv); // Initialise la bibliothèque GLUT
initialiserFenetre(&idFenetre);
initialiserOpenGL();
initialiserVariables();
/*** Boucle principale ***/
glutReshapeFunc(rafraichir);
glutIdleFunc(callBackFonction);
glutDisplayFunc(afficher);
glutMouseFunc(souris);
glutKeyboardFunc(clavier);
glutMainLoop();
return 0;
}
et mes headers socket,serveur,client....
/************ socket.h ****************/
#ifndef __SOCKET__
#define __SOCKET__
#include <iostream.h>
#define TAILLE_BUFFER_SOCKET 1024
#define PORT_PAR_DEFAUT 5500
#define TYPE_SOCKET_PAR_DEFAUT SOCK_STREAM
#define FAMILLE_SOCKET_PAR_DEFAUT AF_INET
#define BLOQUER_RECEPTION 0
#define BLOQUER_EMISSION 1
#define BLOQUER_RECEPTION_EMISSION 2
/**************************/
/* MA CLASSE SOCKET
/**************************/
class socketReseau
{
private :
SOCKADDR_IN socketAdresseIn;
int socketType;
int socketProtocol;
SOCKET socketConnexion;
char* bufferEntree;
char* bufferSortie;
public:
socketReseau()
{
memset(&socketAdresseIn, 0, sizeof(socketAdresseIn));
socketAdresseIn.sin_family = FAMILLE_SOCKET_PAR_DEFAUT;
socketAdresseIn.sin_port = htons(PORT_PAR_DEFAUT);
//socketAdresseIn.sin_addr.s_addr = INADDR_ANY;
socketType = TYPE_SOCKET_PAR_DEFAUT;
bufferEntree = new char [TAILLE_BUFFER_SOCKET];
bufferEntree[0] = '\0';
bufferSortie = new char [TAILLE_BUFFER_SOCKET];
bufferSortie[0] = '\0';
socketConnexion = INVALID_SOCKET;
evenementReseau = NULL;
}
~socketReseau()
{
int erreur = 0;
erreur = closesocket(socketConnexion);
if (erreur == SOCKET_ERROR)
{
cerr << "Erreur a la fermeture du socketReseau" << WSAGetLastError() << endl;
}
else
{
cout << "fermeture socketReseau reussi" << endl;
}
cout << "Destructeur Socket " << endl;
}
SOCKADDR_IN* lireSocketAdresseInRef(void) { return(&socketAdresseIn); }
SOCKADDR_IN lireSocketAdresseIn(void) { return(socketAdresseIn); }
char* lireAdresseSocketAdresseIn(void) { return(inet_ntoa(socketAdresseIn.sin_addr)); }
int lireSocketType(void) { return(socketType); }
int lireSocketProtocol(void) { return(socketProtocol); }
int lireFamilleSocketAdresseIn(void) { return(socketAdresseIn.sin_family); }
unsigned short lirePortSocketAdresseIn(void) { return(socketAdresseIn.sin_port); }
SOCKET lireSocketConnexion(void) { return(socketConnexion); }
SOCKET* lireSocketConnexionRef(void) { return(&socketConnexion); }
char* lireBufferEntree(void) { return(bufferEntree); }
char* lireBufferSortie(void) { return(bufferSortie); }
void ecrireAdresseSocketAdresseIn(char* a);
void ecrireAdresseSocketAdresseInLocal(void);
void ecrireSocketType(int t) { socketType = t; }
void ecrireSocketProtocol(int p) { socketProtocol = p; }
void ecrireSocketConnexion(SOCKET s) { socketConnexion = s; }
void ecrireFamilleSocketAdresseIn(int f) { socketAdresseIn.sin_family = f; }
void ecrirePortSocketAdresseIn(unsigned short& p) { socketAdresseIn.sin_port = htons(p); }
void ecrireBufferEntree(char* chE) { bufferEntree = chE; }
void ecrireBufferSortie(char* chS) { bufferSortie = chS; }
int bindSocket(void);
int creerSocket(void);
int envoyer(void);
int recevoir(void);
void fermerSocket(void);
int bloquerSocket(void);
};
/*** Initialiser la version de Winsock et demarre Winsock ***/
int initialiserWinsock(void);
#endif
/************ socket.h ****************/
/**************************/
/* MA CLASSE SERVEUR
/**************************/
le type Liste est une liste dynamique sur un type quelconque
elle derive de socketReseau
/************ serveur.h ****************/
#ifndef __SERVEUR__
#define __SERVEUR__
#include "listeGenerique.h" // Listes génériques
#include "listeTemplate.h" // Listes templates
#include "socket.h"
#define SERVEUR_PRET true
#define SERVEUR_INDISPONIBLE false
class serveur : public socketReseau
{
private :
bool status;
int connexionMax;
Liste<socketReseau> listeSocketsClients;
public:
serveur()
{
status = false;
connexionMax = 5;
listeSocketsClients.creerListe(socketReseau(), 1); // ici je cree une cellule socketReseau destine a recevoir le client
}
~serveur();
void creerListeSocketsClients(int nbC)
{
listeSocketsClients.creerListe(socketReseau(), nbC);
}
bool lireStatus(void) { return(status); }
void ecrireStatus(bool s) { status = s; }
char* AdresseIpDuClient(int numC);
int envoyerClient(int numC, char* chOut);
char* recevoirClient(int numC);
int envoyerClients(char* chOutAll);
int recevoirClients(char* chInAll);
int demarrerServeur(unsigned short & port, int socType, int socFam);
int ecouter(void);
int attenteConnexionsClients(void);
void arreterServeur(void);
};
#endif
/************ serveur.h ****************/
/**************************/
/* MA CLASSE CLIENT
/**************************/
#ifndef __CLIENT__
#define __CLIENT__
#include "socket.h"
class client : public socketReseau
{
private :
char* adresseIPServeur;
public:
client(void) { }
~client(void) { }
char* lireAdresseIPServeur() { return(adresseIPServeur); }
void ecrireAdresseIPServeur(char* ch) { adresseIPServeur = ch;}
int connexionServeur(char* adresseIPServeur, unsigned short & port, int socType, int socFam);
int Connecter();
void arreterClient();
};
#endif
/************ serveur.h ****************/
voici un aperçu du serveur.cpp
/*** Destructeur ***/
serveur::~serveur()
{
int k = 0;
int erreur = 0;
erreur = closesocket(listeSocketsClients[k].lireSocketConnexion());
if (erreur == SOCKET_ERROR)
{
cerr << "Erreur Fermeture Socket Client pendant l'arret du serveur :" << WSAGetLastError() << endl;
}
WSACleanup(); // arret de winsock
listeSocketsClients.detruireListe();
}
int serveur::demarrerServeur(unsigned short & port, int socType, int socFam)
{
int erreur = 0;
this -> ecrireFamilleSocketAdresseIn(socFam);
this -> ecrireSocketType(socType);
this -> ecrireAdresseSocketAdresseInLocal();
this -> ecrirePortSocketAdresseIn(port);
this -> creerSocket();
this -> bindSocket();
if (this -> lireSocketConnexion() != INVALID_SOCKET)
{
cout << "SOCKET SERVEUR CREE AVEC SUCCES" << endl;
cout << "ADRESSE : " << lireAdresseSocketAdresseIn() << endl;
cout << "PORT : " << lireSocketAdresseIn().sin_port << endl;
return(0);
}
else
{
cerr << "ERREUR LORS DE LA CREATION DU SOCKET SERVEUR" << endl;
erreur = closesocket(this -> lireSocketConnexion());
if (erreur == SOCKET_ERROR)
{
cerr << "Erreur fermeture socket serveur lors du demarrage suite a une erreur a la creation : " << WSAGetLastError() << endl;
WSACleanup(); // arret de winsock
return(INVALID_SOCKET);
}
return(INVALID_SOCKET);
}
return(0);
}
/*** Mise en ecoute du serveur ***/
int serveur::ecouter(void)
{
if (listen(this -> lireSocketConnexion(), 0) == 0)
{
cout << "PASSAGE EN ECOUTE DU SERVEUR REUSSI" << endl;
return(0);
}
else
{
cerr << "ERREUR LORS DU PASSAGE EN ECOUTE DU SERVEUR : " << WSAGetLastError() << endl;
}
return(SOCKET_ERROR);
}
/*** Attendre la connexion du client ***/
int serveur::attenteConnexionsClients(void)
{
int tailleAdresse = 0;
tailleAdresse = sizeof(struct sockaddr_in);
listeSocketsClients[0].ecrireSocketConnexion(accept(this -> lireSocketConnexion(), (SOCKADDR*)listeSocketsClients[0].lireSocketAdresseInRef() ,&tailleAdresse));
if (listeSocketsClients[0].lireSocketConnexion() != INVALID_SOCKET)
{
cout << "CONNECTION CLIENT ACCEPTEE" << endl;
cout << "ADRESSE DU CLIENT : [" << listeSocketsClients[0].lireAdresseSocketAdresseIn() << "]" << endl;
return(0);
}
else
{
cerr << "ERREUR LORS DU L'ACCEPTATION DU CLIENT : %d\n" << WSAGetLastError() << endl;
return(SOCKET_ERROR);
}
return(0);
}
merci d'avance !!
kawito