Comment Gerer des sockets non bloquant sous OpenGl

cs_kawito Messages postés 24 Date d'inscription dimanche 20 juillet 2003 Statut Membre Dernière intervention 13 décembre 2005 - 20 juil. 2003 à 17:34
kwisatz_haderach Messages postés 5 Date d'inscription mardi 23 décembre 2003 Statut Membre Dernière intervention 3 janvier 2004 - 3 janv. 2004 à 14:16
Bonjour,

je devellope un jeu (2d + scene 3d) en Opengl et C++, je desire utiliser seulement opengl et c++ (console app), pour des raisons de portabilitée,donc pas de MFC !
et biensur j'aimerais que ce jeu ce joue en reseau :

j'ai donc fais un client serveur tcp (winsock version 1.1)
mais les fonction accept et recv sont bloquante ,

mon serveur passe en ecoute ,puis je fais un accept sur le socket client (1er client)
la fonction accept et bloquante !
j'ai donc cherché comment faire pour eviter ce probleme, et la je bloque un peu ?
j'ai bien vu des truc comme SWAAsyncSelect(socket,hWnd,wMsg,Event);

comment reccuperer les messages de windows wMsg sous opengl et l'identificateur de la fenetre ?
pour que je puisse utiliser les fonctions du type WSA

je voudrais que le serveur detecte une nouvelle connexion cliente :
une fois mon serveur en ecoute je voudrais qu'il scrute les evenements network, pour faire selon un accept un send ou un recv.
le serveur possede une liste dynamique de socket client

si evenement network FD_ACCEPT
creer cellule socket cliente
faire un accet sur ce socket
connexion acceptée ?

scruter les evenements j'usqu'au prochain accept et on recommence, creation de la cellule socket cliente et accept...

ainsi je pense que meme si la fonction accept et bloquante
vu que je detecte une demande de connexion avant de lancer la fonction accept, cela devrais fonctionner ?

ou peut etre faut il utiliser les threads ,mais la j'ai pas tous compris !
comment utiliser un thread sous opengl sans MFC

AUTRE SOUCIS :

j'utilise winsock 1.1 car losrque j'inclus winsock2.h
avec la lib ws2_32.lib
j'ai des erreurs sur fd_set redefined etc......
impossible d'utiliser winsock version 2 !

ya t'il un probleme dans windows.h, il me semble que winsock.h est systematiquement implementé ,ou quil manque des directives dans winsock2.h ?

AUTRE QUESTION:

quel est l'architecture d'un programme complex en opengl sans MFC,ou placer les traitements du programme ?
comme la getion des sockets reseau

glutReshapeFunc(rafraichir);
glutIdleFunc(callBackFonction);
glutDisplayFunc(afficher);
glutMouseFunc(souris);
glutKeyboardFunc(clavier);

merci a vous de me donner un coup de main

5 réponses

cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
20 juil. 2003 à 19:34
Salut,

1) WSA=> windows socket api => winsock 2
Donc je pense pas que tu puisse utiliser les fonctions WSA en socket 1.1.

2) Ensuite, la fonction WSAAsyncSelect transcrit les evenement reseau en messages windows, donc il te faut une fenetre (meme invisible) pour recevoir et traiter les messages.
Pour detecter et accepter une nouvelle connection, tu traite FD_ACCEPT. Dans ce message, ou plutot cette notification de message, tu met tout tes trucs: tu crée tes cellules, tu accepte la connection... Si accept retourne autre chose que INVALID_SOCKET, c'est que la connection a reussi.

3) Enfin, pour les erreurs de definition,
- soit tu inclus winsock2.h avant windows.h (ca c si tu as juste des probs de redefinition avec winsock2.h)
- soit tu met tout en haut, avant tout les header:
#define _WIN32_WINNT 0x0500
(c'est le mieux)

4) J'y connais rien en OPENGL, désolé.
0
cs_Manson Messages postés 137 Date d'inscription lundi 17 décembre 2001 Statut Membre Dernière intervention 30 septembre 2004
21 juil. 2003 à 11:16
salut,

moi je dirais que tu initialise la dll donc avec un WSAStartup,
ensuite tu initialiase la socket du "server", tu cree un nouveau thread dans lequel tu fais tourner un select (c'est mieux, 'fin je trouve) et enfin en fonction des FD tu transcrit le msg.

Bon courage.

Arno
0
cs_kawito Messages postés 24 Date d'inscription dimanche 20 juillet 2003 Statut Membre Dernière intervention 13 décembre 2005
21 juil. 2003 à 21:26
Salut,

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)

l idée du thread, j'y ais bien pensais ,mais j'ai pas tout compris comment faire,declarer un thread et comment l'implenter dans mon programme...

vu mon architecture quel est la meilleur methode, et ne pas oublier que j'utilise GLUT et c++ en console application

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
#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);
}
0
cbestern Messages postés 25 Date d'inscription jeudi 19 décembre 2002 Statut Membre Dernière intervention 17 novembre 2003
16 août 2003 à 13:41
en quelques mots pour les thrad:
définir 2 handle, 1 pour le thread et un pour l'évenement
(un évenement est soit signer soit non signer comme un bolleen)
HANDLE HandTread= NULL;
HANDLE HandEvent=NULL;

//définit ta fonction thread (qui se nome ici FonctionThread)
DWORD FonctionThread(LPVOID)
{
//ici il boucle juqu'a l'arriver de l'évement

while(WaitForSingleObject(HandEventEm,0)!=WAIT_OBJECT_0)
{
//fait Ce que tu veut!!!
}
}

//pour le lancer
void StartThread()
{
assert(!HandTread);
assert(!HandEvent);

HandEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
DWORD ThreadIDRe;
//c ici même qu'il crée le thread
HandTread = CreateThread(NULL,0,FonctionThread,NULL,0,&ThreadIDRe);
}

//et pour l'arrêter:
void Stopthread()
{
assert(HandTread);
assert(HandEvent);
//signale l'évenement pour le faire sortir de sa boucle
SetEvent(HandEvent);
WaitForSingleObject(HandEvent,INFINITE);
CloseHandle(HandTread);
CloseHandle(HandEvent);
HandTread = NULL;
HandEvente = NULL;
}

Bon ça c pour une utilisation normale, juste un petit truc, il ne faut pas que ton programme finisse avant ton thread.

j'espere avoir été assez clair.
Sinon regarde les exemples de client serveurs, ça pourrais t'aider
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
kwisatz_haderach Messages postés 5 Date d'inscription mardi 23 décembre 2003 Statut Membre Dernière intervention 3 janvier 2004
3 janv. 2004 à 14:16
Bonjour,
je fais le meme programme que toi : jeu openGL/C++ mais en utilisant DirectX pour l'input et l'audio (en prévision de rester sous Windows comme OS)
Si tu veux rajouter la fonctionnalité réseau, il faut créer une thread spécial réseau...
Le serveur possède 2 threads :
- ca boucle principal (thread SERVER_MAIN ) où il écoute, dispatche et envoie les informations aux sockets connectés
- une autre thread WAIT_CONNECTION qui s'occupe juste d'accepter les connections pour les ajouter au tableau des connectés.

Théoriquement dans la plupart des jeux que nous connaissons, la thread WAIT_CONNECTION est disponible qu'au moment où par exemple dans un wargame, on crée la salle et les autres rejoignent. Ensuite pendant le jeu, aucune connexion n'est souvent permise mais rien ne t'empeche de le faire comme tu le désires.

Pour t'expliquer les thread, je sais pas si tu aimes les articles en anglais mais voici la source que je me sers pour créer mes threads.. c'est une classe que je n'ai pas modifié dont je fais hérité mes classes thread comme networkThread ou encore gamecoreThread.... totalement compatible application dos par contre ce n'est pas cross-plateformable (ca existe comme mot ???) puisque sous unix/linux on utilise des commandes C systèmes pour créer les threads (enfin, je devrais dire "processus")

J'espère t'avoir un peu aider dans ta recherche...

le lien vers l'article Encapsulating Win32 threads in C++
http://www.codeproject.com/threads/thread_win32.asp
0
Rejoignez-nous