Gestion des event avec WSANETWORKEVENTS

Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 - 10 déc. 2004 à 19:11
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 - 27 déc. 2004 à 16:20
bonjour à tous,
je voudrais votre avis sur la gestion des evenements sur les sockets.
je réalise une application (un jeu) qui doit communiquer sur un réseau local. j prévois donc d'utiliser 2 thread, un d'envoi et un de reception.

j'ai plusieurs pb:
- la gestion des evenement ne marche pas, en effet, je crée bien les evenements avec (WSACreateEvent) et je les assigne au socket (WSAEventSelect). par contre, le pb se situe j pense au niveau de l'attente d'evenement (WSAWaitForMultipleEvents) parce que le programme semble se bloquer à ce niveau.

- de plus, lors de la gestion du serveur, je ne vois pas comment gérer les evenements après acceptation de la connexion (accept) car il y a création d'un autre socket pour les communication.
(j'ai bien lu l'histoire dans laquelle on crée un tableau cf le livre conseillé par aardman qui est tres bien; mais j n'arrive pas à l'implémenter) j'ai donc choisi de créer un autre évenement sans faire tte l'histoire du tableau mais ca ne marche pas, le prog se bloque à nouveau sur WSAWaitForMultipleEvents.

- enfin rassurez moi, il m'a semble que d'utiliser la gestion de socket avec WSAWaitForMultipleEvents etait un bon choix, j'ai bon...??

Désolé pour la longueur du post, et pour ceux qui auront le courage de lire, merci beaucoup pour vos réponses.

//
// Voila le Code Client:
//

#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

int main(int argc, char ** argv)
{
char buffer[250];
int N_port = 6566; // numero du port de communication
int QUEUE = 5; // taille de la file d'attente pour la connection sur le listen socket
SOCKET C_socket;
SOCKADDR_IN C_adresse; // adresse du client

WSAEVENT hEvent[1];
WSANETWORKEVENTS NetworkEvent;

printf("Chat Client\n");

// initialisation de la connection
C_socket = socket(AF_INET, SOCK_STREAM, 0);
if(C_socket == -1)
{
printf("ERREUR : echac de la création de socket\n");
}

C_adresse.sin_family = AF_INET;
C_adresse.sin_port = htons(N_port);
C_adresse.sin_addr.s_addr = inet_addr("127.0.0.1");

hEvent[0] = WSACreateEvent();
WSAEventSelect(C_socket, hEvent[0], FD_WRITE | FD_READ | FD_CONNECT | FD_CLOSE);

printf("Demande de connexion au serveur 127.0.0.1\n");
connect(C_socket, (sockaddr*)&C_adresse, sizeof(C_adresse));

// Boucle de gestion des evenements
while(true)
{
printf("Client Gestion Event\n");

memset(&NetworkEvent, 0, sizeof(NetworkEvent));
WSAWaitForMultipleEvents(1, hEvent, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(C_socket, hEvent[0], &NetworkEvent);

if(NetworkEvent.lNetworkEvents & FD_CONNECT)
{
printf("Client Event Connect\n");
// erreur a la connexion
if(NetworkEvent.iErrorCode[FD_CONNECT_BIT])
{
printf ("ERREUR : Connexion error\n");
break;
}
// si connexion ok, envoi de la requete
}

if (NetworkEvent.lNetworkEvents & FD_WRITE)
{
printf("Client Event Write\n");
if (NetworkEvent.iErrorCode[FD_WRITE_BIT] != 0)
{
printf("FD_WRITE failed with error %d\n", NetworkEvent.iErrorCode[FD_WRITE_BIT]);
break;
}
// envoie de données
send(C_socket,
buffer,
sizeof(buffer),
0);
}

if(NetworkEvent.lNetworkEvents & FD_READ)
{
printf("Client Event Read\n");
// erreur a la connexion
if(NetworkEvent.iErrorCode[FD_READ_BIT])
{
printf ("ERREUR : Read error\n");
break;
}
// lecture de donnees sur le socket
recv(C_socket,buffer, sizeof(buffer), 0);
}

if(NetworkEvent.lNetworkEvents & FD_CLOSE)
{
printf("Client Event Close\n");
// verifie s'il ne reste plus rien a lire sur le socket
do
{
memset(&NetworkEvent, 0, sizeof(NetworkEvent));
WSAEnumNetworkEvents(C_socket, 0, &NetworkEvent);
if(NetworkEvent.lNetworkEvents & FD_READ)
{
if(NetworkEvent.lNetworkEvents & FD_READ)
{
// erreur a la connexion
if(NetworkEvent.iErrorCode[FD_READ_BIT])
{
printf ("ERREUR : Read error\n");
break;
}
// lecture de donnees sur le socket
recv(C_socket,buffer, sizeof(buffer), 0);
}
}
}
while(NetworkEvent.lNetworkEvents & FD_READ);

}
}
return 0;
}

//
// Voila le Code Serveur:
//

// serveur.cpp : Defines the entry point for the console application.
//
#include "string.h"
#include "stdio.h"
#include "conio.h"
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")

void accept(void);

int main(int argc, char* argv[])
{
char buffer[250];
SOCKET L_socket; // socket pour ecoute sur le reseau (listen)
SOCKET S_socket; // socket Serveur pour emission/reception sur le reseau

SOCKADDR_IN S_adresse; // adresse du serveur

int N_port = 6667; // numero du port de communication
int QUEUE = 5; // taille de la file d'attente pour la connection sur le listen socket

int Ret;
WSADATA WSAData;

WSAEVENT hEvent[2];
WSANETWORKEVENTS NetworkEvent,NewEvent;

printf("Chat Serveur !\n");

// initialisation de la connexion

if ((Ret = WSAStartup(MAKEWORD(2,2), &WSAData)) != 0)
{
printf("ERREUR :WSAStartup a echoue",Ret);
return (-1);
}

L_socket = socket( AF_INET,SOCK_STREAM,IPPROTO_TCP);
S_adresse.sin_family = AF_INET;
S_adresse.sin_addr.s_addr = htonl(INADDR_ANY);
S_adresse.sin_port = htons(N_port);

bind( L_socket,(SOCKADDR *)&S_adresse,sizeof(S_adresse));

// creation d'un evenement reseau
hEvent[0] = WSACreateEvent();

WSAEventSelect(L_socket, hEvent[0], FD_ACCEPT | FD_CLOSE);

listen(L_socket, QUEUE);

while(TRUE)
{
memset(&NetworkEvent, 0, sizeof(NetworkEvent));
WSAWaitForMultipleEvents(1, hEvent, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(L_socket, hEvent[0], &NetworkEvent);

// Check for FD_ACCEPT messages
if (NetworkEvent.lNetworkEvents & FD_ACCEPT)
{
printf("Serveur Event Accept\n");
if (NetworkEvent.iErrorCode[FD_ACCEPT_BIT] != 0)
{
printf("FD_ACCEPT failed with error %d\n",NetworkEvent.iErrorCode[FD_ACCEPT_BIT]);
break;
}

// Accept a new connection, and add it to the
// socket and event lists
accept();
}

if (NetworkEvent.lNetworkEvents & FD_CLOSE)
{
printf("Serveur Event Close\n");
if (NetworkEvent.iErrorCode[FD_CLOSE_BIT] != 0)
{
printf("FD_CLOSE failed with error %d\n",NetworkEvent.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(S_socket);
}
}

// fermeture du socket
//--------------------
closesocket(S_socket);
closesocket(L_socket);

// liberation des ressources allouées pour la communication
//---------------------------------------------------------
if (WSACleanup() == SOCKET_ERROR)
{
printf("ERREUR : WSACleanup a echoue, erreur : %d\n", WSAGetLastError());
}
return 0;
}

void accept(void)
{
printf("Serveur ConneX Accept\n");

S_socket = accept(
L_socket,
NULL,
NULL);

// send de test
send(S_socket,
"ca marche",
9,
0);

hEvent[1] = WSACreateEvent();

WSAEventSelect(
S_socket,
hEvent[1],
FD_READ | FD_WRITE | FD_CLOSE);

while(true)
{
memset(&NewEvent, 0, sizeof(NewEvent));

WSAWaitForMultipleEvents(1, hEvent, 0, WSA_INFINITE, 0);
WSAEnumNetworkEvents(S_socket, hEvent[1], &NewEvent);

// Process FD_READ notification
if (NewEvent.lNetworkEvents & FD_READ)
{
printf("Serveur Event Read\n");
if (NewEvent.iErrorCode[FD_READ_BIT] != 0)
{
printf("FD_READ failed with error %d\n", NewEvent.iErrorCode[FD_READ_BIT]);
break;
}

// Read data from the socket
recv(S_socket,buffer, sizeof(buffer), 0);
}

// Process FD_WRITE notification
if (NewEvent.lNetworkEvents & FD_WRITE)
{
printf("Serveur Event Write\n");
if (NewEvent.iErrorCode[FD_WRITE_BIT] != 0)
{
printf("FD_WRITE failed with error %d\n", NewEvent.iErrorCode[FD_WRITE_BIT]);
break;
}

send(S_socket,
buffer,
sizeof(buffer),
0);
}

if (NewEvent.lNetworkEvents & FD_CLOSE)
{
printf("Serveur Event Close\n");
if (NewEvent.iErrorCode[FD_CLOSE_BIT] != 0)
{
printf("FD_CLOSE failed with error %d\n",NewEvent.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(S_socket);
}
}

}

36 réponses

Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
14 déc. 2004 à 10:56
je dois pas avoir bie, compris ce que tu voulais dire, j'ai été voir sur les msdn, mais mon code reprend exactement leur exemple (il doit etre trop simpliste).

perso j'ai compris que plusieurs event pouvaient arriver en mm tps sur le mm socket, on a donc WSAWaitForMultipleEvents qui retourne (mais en fait plusieurs event sont actif) et il faut donc tous les tester.
donc mon cas j'utilise 4 event different: FD_READ FD_WRITE FD_ACCEPT FD_CLOSE, il faut donc que j fasse 4 fois WSAEnumNetworkEvent... c'est ca?

on aurait:
Index = WSAWaitForMultipleEvents(EventTotal,EventArray, FALSE, WSA_INFINITE, FALSE);

Index = Index - WSA_WAIT_EVENT_0;


for(i=Index; i < EventTotal ;i++)
{
Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, FALSE);
if ((Index != WSA_WAIT_FAILED) || (Index != WSA_WAIT_TIMEOUT))
{
for (j=0;j<4;j++)
{
Index = i;
WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvent);
//
// traitement de chaque type d'event
//
}
}
}
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
14 déc. 2004 à 11:02
au fait pour la fonciton CompressArrays il faut charger qqch de particulier ou pas?
pq j'ai essayé de l'utiliser, mais :
error C2065: 'CompressArrays' : undeclared identifier

et sur les msdn la recherche à error C2065: 'CompressArrays' n'a rien donné...
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
14 déc. 2004 à 12:33
Salut,
undeclared identifier ? CompressArrays n'est pas une api, mais une fonction que tu dois coder toi meme.

"donc mon cas j'utilise 4 event different: FD_READ FD_WRITE FD_ACCEPT FD_CLOSE, il faut donc que j fasse 4 fois WSAEnumNetworkEvent... c'est ca?"
>> pas du tout, tu as autant d'event que de socket.
Imagine tu as 3 clients qui envoient en meme temp 3 messages sur le serveur. Tu va avoir 3 events qui vont passer a l'état signalés, il faut appeler WSAEnumNetworkEvent pour chaque event, et il faut gerer l'evenement FD_READ pour chaqu'un des 3 clients...
En fait, il faut gerer les evenement FD_CONNECT FD_READ FD_WRITE FD_ACCEPT FD_CLOSE dans une fonction, et appeler cette fonction 1 fois pour chaque event signalé.

Dans l'exemple de serveur du bouquin, c'est la fonction HandleIo qui fait cela (a etudier). D'ailleur dans cet exemple, tu dois aussi trouver la fonction CompressArrays.

http://betouchi.free.fr/doc_et_ebook/prog_reseau/exemples-network2.zip
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
14 déc. 2004 à 18:43
ok voila qui explique pas mal de chose...

et enfin un nouveau livre à lire... (en anglais j'espere lol)

j'ecris pas plus de connerie j lis ton livre et j dirais ou j'en suis apres...

merci
0

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

Posez votre question
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
14 déc. 2004 à 23:57
ok j'ai lu un peu le livre, et les exemples dont tu parles et voila ce que j'ai vu:

while (1)
{
rc = WaitForMultipleObjects(
thread->SocketCount + 1,
thread->Handles,
FALSE,
INFINITE);

for(i=0; i < thread->SocketCount + 1 ;i++)
{
rc = WaitForSingleObject(thread->Handles[i], 0);if (rc WAIT_FAILED || rc WAIT_TIMEOUT)
{
// traitement erreur
}

index = i;

// Enumerate the events
rc = WSAEnumNetworkEvents(
sock->s,
sock->event[index],
&nevents);

// traitement de chaque exeption
}
}

Le pb c'est que je vois mal la difference avec ce que j fais:

while (true)
{
// Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,EventArray, FALSE, WSA_INFINITE, FALSE);
// permet de deduire de quel socket vient l'evenement
Index = Index - WSA_WAIT_EVENT_0;

// Iterate through all events to see if more than one is signaled
for (i=Index; i < EventTotal ;i++)
{
Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, FALSE);
if ((Index != WSA_WAIT_FAILED) || (Index != WSA_WAIT_TIMEOUT))
{
Index = i;

WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvent);

// Check for FD_XXXmessages
}
}
}

en gros a part la fonction waitforsingleobject (qui d'ailleurs n'est pas une fction winsock, je l'ai pas vu sur msdn, et qui en plus n'est pas codee dans l'exple), ca me semble asser proche, je ne vois pas bien pkoi mon code ne teste pas les events de chaque socket puisque:

for (i=Index; i < EventTotal ;i++)
{
Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, FALSE);

ca devrait tester ts les events que l'on a cree et comme ils sont tous assignés à un socket ca me donne l'impression que l'on teste chaque type d'event pour chaque event (et donc socket) créé avec l'interieur de la boucle for:

Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, FALSE);
if ((Index != WSA_WAIT_FAILED) || (Index != WSA_WAIT_TIMEOUT))
{
Index = i;

WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvent);

// Check for FD_XXXmessages
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
15 déc. 2004 à 00:19
Salut,
//
// Function: ChildThread
//
// Description:
// This is the child thread that handles socket connections. Each thread
// can only wait on a maximum of 63 sockets. The main thread will assign
// each client connection to one of the child threads. If there is no
// thread to handle the socket, a new thread is created to handle the
// connection.
//
DWORD WINAPI ChildThread(LPVOID lpParam)
{
THREAD_OBJ *thread=NULL;
SOCKET_OBJ *sptr=NULL,
*sockobj=NULL;
int index,
rc,
i;

thread = (THREAD_OBJ *)lpParam;

while (1)
{
rc = WaitForMultipleObjects(
thread->SocketCount + 1,
thread->Handles,
FALSE,
INFINITE
); if (rc WAIT_FAILED || rc WAIT_TIMEOUT)
{
fprintf(stderr, "ChildThread: WaitForMultipleObjects failed: %d\n", GetLastError());
break;
}
else
{
// Multiple events may be signaled at one time so check each
// event to see if its signaled
//
for(i=0; i < thread->SocketCount + 1 ;i++)
{
rc = WaitForSingleObject(thread->Handles[i], 0);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "ChildThread: WaitForSingleObject failed: %d\n", GetLastError());
ExitThread(-1);
}
else if (rc == WAIT_TIMEOUT)
{
// This event isn't signaled, continue to the next one
continue;
}

index = i;

if (index == 0)
{
// If index 0 is signaled then rebuild the array of event
// handles to wait on
WSAResetEvent(thread->Handles[index]);

RenumberThreadArray(thread);

i = 1;
}
else
{
// Otherwise, its an event associated with a socket that
// was signaled. Handle the IO on that socket.
//
sockobj = FindSocketObj(thread, index-1);
if (sockobj != NULL)
{
if (HandleIo(thread, sockobj) == SOCKET_ERROR)
{
RenumberThreadArray(thread);
}
}
else
{
printf("Unable to find socket object!\n");
}
}
}
}
}

ExitThread(0);
return 0;
}

Bon, alors au debut de la boucle while, on appele WaitForMultipleObjects.
On traite la valeur de retour (WAIT_FAILED ou WAIT_TIMEOUT si erreur).
S'il n'y a pas d'erreur, on boucle dans le tableau d'event.
POUR CHAQUE EVENT:
on appele WaitForSingleObject (qui est une api, cherche mieux sur msdn).
Puis on teste la valeur de retour de WaitForSingleObject (WAIT_TIMEOUT ou WAIT_FAILED si erreur).
Si pas d'erreur, si pas de timeout, on a bien un event signalé: et on appele HandleIo.

HandleIo: appele WSAEnumNetworkEvent pour l'event concerné, et traite tout les cas possibles: FD_READ, FD_WRITE, etc...
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
15 déc. 2004 à 14:00
euh oui mais donc alors là j'ai une révélation...
dans l'exemple, le truc bizarre c'est qu'il n'utilise que les fonctions WaitForMultipleObjects et WaitForSingleObject qui sont des foncitons de synchronisation de thread (c pour ca que j l'ai pas trouver dans la lib winsock2) alors que moi j'utilise les fonctions WSAWaitForMultipleObjects... idem pour les events avec WSACreateEvent vs CreateEvent.
en fait le pb c'est que il cree des events de threads et les gere avec les fctions winsocks c possible ca??

pq en fait j pensais que les WSAEvent n'etait pas compatible avec les event de gestion des threads... mais apparement si.
du coup il faut connecter WaitForSingleObject(thread->Handles[i], 0); avec tt les events crees pour chaque socket (le tab EventArray[])

en fait, on verifie avec wsawaitformultipleobject qu'il y a eu un event, et on cherche quel l'event declenché en parcourant le tab d'event et en testant avec waitforsingleobject (comme on parcourt tt le tableau, si il y en a eu plusieurs d'un coup, ils seront tous detectés)

j'ai bien compris là ou aps?
j vais essayer d'implementer ca ce soir.

thx pour l'aide
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
15 déc. 2004 à 17:28
Salut,
Et oui ce sont exactement les meme fonctions, sauf qu'ils ont mis un WSA devant, en fait.
Pareil pour les events, les event winsock et les events window c'est exactement la meme chose.
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
15 déc. 2004 à 19:07
ok donc voila ce que ca devrait donner, là on verifie bien si il y a des evenements signalés pour chaque socket.

ps ca marche bien mais la gestion des events est elle bien ce qu'elle doit etre... (je me suis pas encore penché sur la fermeture du socket)

printf("en attente de demande de connexion\n");

while(TRUE)
{
// Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,EventArray, FALSE, WSA_INFINITE, FALSE);
// permet de deduire de quel socket vient l'evenement
Index = Index - WSA_WAIT_EVENT_0;

// Iterate through all events to see if more than one is signaled
for(i=0; i < EventTotal ;i++)
{
int rc;
// on verifie si l'event est signalé
rc = WaitForSingleObject(EventArray[i], 0);
if (rc != WAIT_FAILED && rc != WAIT_TIMEOUT)
{
// si oui, on traite l'event
Index = i;

WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvent);

// Check for FD_ACCEPT messages
if (NetworkEvent.lNetworkEvents & FD_ACCEPT)
{
if (NetworkEvent.iErrorCode[FD_ACCEPT_BIT] != 0 && EventTotal >= NB_CONNEC_MAX)
{
printf("FD_ACCEPT failed with error %d\n",NetworkEvent.iErrorCode[FD_ACCEPT_BIT]);
break;
}

printf("reception et acceptation de la connexion\n");

// Accept a new connection, and add it to the
// socket and event lists
int taille_adr = sizeof (S_adresse);
S_socket = accept(L_socket, (SOCKADDR *)&S_adresse, &taille_adr);

// creation d'un evenement reseau
NewEvent = WSACreateEvent();

WSAEventSelect(S_socket, NewEvent, FD_CLOSE | FD_READ | FD_WRITE);

SocketArray[EventTotal] = S_socket;
EventArray[EventTotal] = NewEvent;
EventTotal++;

printf("connexion acceptee\n\n\n");
}

if(NetworkEvent.lNetworkEvents & FD_READ)
{
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
15 déc. 2004 à 19:12
quoique là la gestion des events se fait bien sur plusieurs sockets, mais comme on ne gere pas le fait qu'il puisse y avoir plusieurs socket ca ne marche pas...
puisqu'on a qu'une seule var S_socket. il en faudrait plus ou alors allouer de la emoire à une structure de socket comme dans l'exple, mais bon dans mon cas, il ne peut y avoir qu'1 seule connexion donc j vais juste protéger la fonction accept pour pas qu'elle ouvre d'autre connexion. non?
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
15 déc. 2004 à 19:26
Salut,
Tu vois bien que dans l'exemple:
S_socket = accept(...); // nouveau socket
NewEvent = WSACreateEvent(); // nouvel event

SocketArray[EventTotal] = S_socket;
EventArray[EventTotal] = NewEvent;
EventTotal++;

Lors d'une connexion, le nouveau socket est ajouté au SocketArray[], et l'event correspondant est ajouté a l'EventArray[].

Donc tu peux gerer plus qu'une connexion.
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
15 déc. 2004 à 22:20
pfff c la misere j'arrete pas de me tromper... oui bien sur t'as raison le pire c'est que je m'etais demandé y'a qlq jour et je l'avais vu...

décidement pô copain les sockets...

bon alors tout ca veut dire que je me suis trompé pq j'ai fait un test et ca ne marche pas du tout. y'a plus qu'a chercher la ptite bete...

:(
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
16 déc. 2004 à 23:54
voila la derniere version du serveur...

ben j'arrive pas a faire dialoguer avce plusieur client en m tps, mais vu que j'utilise les consoles, j pense que le pb vient peut etre de là...

faudra voir à coder la fonction de nettoyage du tableau...

//
// SERVEUR
//

#include "string.h"
#include <stdlib.h>
#include "stdio.h"
#include "conio.h"
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")

// Définition des variables Globables :
//-------------------------------------
#define NB_CONNEC_MAX 2

SOCKET L_socket; // socket pour ecoute sur le reseau (listen)
SOCKET S_socket; // socket Serveur pour emission/reception sur le reseau

// prototype du thread
DWORD WINAPI ThreadServeur(LPVOID lpParam);

int main(int argc, char* argv[])
{

char *Sbuffer;
Sbuffer = (char*)malloc(250);
Sbuffer = strdup ("envoi du serveur");

printf("CHAT SERVEUR\n");

DWORD ThreadId;
// On démarre le thread. ThreadClient est l'identifiant du thread
// ThreadId ne nous est d'aucune utilité dans cet exmple car le thread se termine de lui même
CreateThread(NULL,NULL,ThreadServeur,NULL,NULL,&ThreadId);

// WaitForSingleObject(hEvent,INFINITE);

// Boucle ppale du CHAT
while (strcmp(Sbuffer,"quit")!=0)
{
// saisie de la chaine
gets (Sbuffer);
// envoi de la chaine
send(S_socket, Sbuffer, strlen(Sbuffer)+1, 0);
}

// fermeture du socket
//--------------------
closesocket(S_socket);

// liberation des ressources allouées pour la communication
//---------------------------------------------------------
if (WSACleanup() == SOCKET_ERROR)
{
printf("ERREUR : WSACleanup a echoue, erreur : %d\n", WSAGetLastError());
}
return 0;
}

// Procédure utilisée par le thread
DWORD WINAPI ThreadServeur(LPVOID lpParam)
{
int k=0,j=0;
int nb_octets;
int Ret;
char buffer[250];

WSADATA WSAData;

SOCKADDR_IN S_adresse; // adresse du serveur

int N_port = 6566; // numero du port de communication
int QUEUE = 5; // taille de la file d'attente pour la connection sur le listen socket

WSAEVENT NewEvent,EventArray[3];
WSANETWORKEVENTS NetworkEvent;
SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS];
DWORD EventTotal = 0;
DWORD Index, i;

// initialisation de Winsock version 2.2
//--------------------------------------
if ((Ret = WSAStartup(MAKEWORD(2,2), &WSAData)) != 0)
{
printf("ERREUR :WSAStartup a echoue",Ret);
return (-1);
}

// Création du socket d'écoute sur le reseau
// (demande de connexion client)
//-------------------------------------------
L_socket = socket( AF_INET, // famille d'adresse du protocol (ici IPv4)
SOCK_STREAM, // type de socket du protocol (ici TPC/IP)
IPPROTO_TCP); // protocol utilisé (ici TCP/IP)

// remplissage de la structure d'adressage winsock
// pour les communication reseau en IPv4
//------------------------------------------------
S_adresse.sin_family = AF_INET;
S_adresse.sin_addr.s_addr = htonl(INADDR_ANY);
S_adresse.sin_port = htons(N_port);

// Bind du Socket
// association de l'adresse avec le socket
//----------------------------------------
bind( L_socket, (SOCKADDR *)&S_adresse, sizeof(S_adresse));

// creation d'un evenement reseau
NewEvent = WSACreateEvent();

WSAEventSelect(L_socket, NewEvent, FD_ACCEPT | FD_CLOSE );

// mise à l'écoute de demande de connection client
// on utilise une file d'attente de 5 place
//------------------------------------------------
listen(L_socket, QUEUE);

SocketArray[EventTotal] = L_socket;
EventArray[EventTotal] = NewEvent;
EventTotal++;

printf("en attente de demande de connexion\n");

while(TRUE)
{
// Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,EventArray, FALSE, WSA_INFINITE, FALSE);
// permet de deduire de quel socket vient l'evenement
Index = Index - WSA_WAIT_EVENT_0;

// Iterate through all events to see if more than one is signaled
for(i=0; i < EventTotal ;i++)
{
int rc;
// on verifie si l'event est signalé
rc = WaitForSingleObject(EventArray[i], 0);
if (rc != WAIT_FAILED && rc != WAIT_TIMEOUT)
{
// si oui, on traite l'event
Index = i;

WSAEnumNetworkEvents(
SocketArray[Index],
EventArray[Index],
&NetworkEvent);

// Check for FD_ACCEPT messages
if (NetworkEvent.lNetworkEvents & FD_ACCEPT)
{
if (NetworkEvent.iErrorCode[FD_ACCEPT_BIT] != 0 && EventTotal >= NB_CONNEC_MAX)
{
printf("FD_ACCEPT failed with error %d\n",NetworkEvent.iErrorCode[FD_ACCEPT_BIT]);
break;
}

printf("reception et acceptation de la connexion\n");

// Accept a new connection, and add it to the
// socket and event lists
int taille_adr = sizeof (S_adresse);
S_socket = accept(L_socket, (SOCKADDR *)&S_adresse, &taille_adr);

// creation d'un evenement reseau
NewEvent = WSACreateEvent();

WSAEventSelect(S_socket, NewEvent, FD_CLOSE | FD_READ | FD_WRITE);

SocketArray[EventTotal] = S_socket;
EventArray[EventTotal] = NewEvent;
EventTotal++;

printf("connexion acceptee\n\n\n");
}

if(NetworkEvent.lNetworkEvents & FD_READ)
{
// erreur a la connexion
if(NetworkEvent.iErrorCode[FD_READ_BIT])
{
printf("FD_READ failed with error %d\n", NetworkEvent.iErrorCode[FD_READ_BIT]);
break;
}
// Read data from the socket
nb_octets = recv(S_socket,buffer, sizeof(buffer), 0);
if (nb_octets != -1)
{
buffer[nb_octets] = '\0';
j++;
printf(">>%d - %s\n",j,buffer);
}
}

if(NetworkEvent.lNetworkEvents & FD_WRITE)
{
// erreur a la connexion
if(NetworkEvent.iErrorCode[FD_WRITE_BIT])
{
printf("FD_WRITE failed with error %d\n", NetworkEvent.iErrorCode[FD_WRITE_BIT]);
break;
}
}

if(NetworkEvent.lNetworkEvents & FD_CLOSE)
{
if (NetworkEvent.iErrorCode[FD_CLOSE_BIT] != 0)
{
printf("FD_CLOSE failed with error %d\n\n\a\n\n",NetworkEvent.iErrorCode[FD_CLOSE_BIT]);
break;
}
// verifie s'il ne reste plus rien a lire sur le socket
do {
memset(&NetworkEvent, 0, sizeof(NetworkEvent));
WSAEnumNetworkEvents(S_socket, 0, &NetworkEvent);
if(NetworkEvent.lNetworkEvents & FD_READ)
{
}
}while(NetworkEvent.lNetworkEvents & FD_READ);

closesocket(SocketArray[Index]);

// Remove socket and associated event from
// the Socket and Event arrays and decrement
// EventTotal
// CompressArrays(EventArray, SocketArray, &EventTotal);
}
}
}
}
}
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
17 déc. 2004 à 00:23
Salut,
Lors tu traitement du FD_READ:
recv(SocketArray[Index], ...);
au lieu de:
recv(S_socket, ...);

je vois pas trop ce que vient faire S_socket ici d'ailleur.
Lorsque l'event EventArray[Index] est a l'état signalé, c'est le socket SocketArray[Index] qui a généré cet evenement, pas un autre.

Quant a la fonction CompressArray:
Lors d'un FD_CLOSE, tu:
- ferme l'event
- ferme le socket
- met l'event a 0
- met le socket a 0

et ta fonction CompressArray devra juste a enlever tout les 0 des deux tableaux.
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
17 déc. 2004 à 01:16
oki ben c'estres clair ton msg j vais implementer tt ce demain ou ce we...
apres la soirée de demain :p

merci
0
Spiffou Messages postés 100 Date d'inscription jeudi 1 avril 2004 Statut Membre Dernière intervention 9 juin 2014 1
27 déc. 2004 à 16:20
voila merci encore pour ton aide, j'ai mis tout ca dans des classes et j'ai posté la source...

d'ailleurs j viens de voir que j'ai mal fait la fction compressarray...
encore un truc à corrigé

;)

http://www.cppfrance.com/code.aspx?ID=28432
0
Rejoignez-nous