Winsock2 WASEvents...

Résolu
Signaler
Messages postés
37
Date d'inscription
mardi 8 juillet 2003
Statut
Membre
Dernière intervention
27 avril 2006
-
Messages postés
37
Date d'inscription
mardi 8 juillet 2003
Statut
Membre
Dernière intervention
27 avril 2006
-
Bonjour à tous,

J'ai une
question concernant winsock2, je souhaite faire un thread d'écoute de
sockets. Mais je souhaite pouvoir ajouter dynamiquement une socket dans
le pool de socket déjà existant.

J'ai fait le code suivant
(issu en grande partie de Sylvain MARECHAL -
sylvain.marechal1@libertysurf.fr) qui se contente de "lever" un event
pour déclencher une réaction (envoie de données ici, mais ce pourrait
être ajout d'une nouvelle socket en écoute).

Le problème est que le ResetEvent semble poser problème...car le WaitForMultipleEvents plante après.

// Ce programme créé 3 sockets :
// La première socket écoute le premier port de libre, la 2° se connecte
// dessus, ce qui crée donc une 3° socket.
//
Après avoir échangé un paquet de données, un event d'administration est
envoyé ce qui doit engendrer l'envoie d'un n ouveau paquet et lors de
la
// réception un nouvel event d'administration doit être généré...
//
/////////////////////////////////////////////////////////////////////////////
#include <winsock2.h>
#include <stdio.h>
#include <conio.h>
#define SOCKET_ERRNO WSAGetLastError()

/////////////////////////////////////////////////////////////////////////////
//
// LISTENFIRSTFREEPORT
/////////////////////////////////////////////////////////////////////////////
//
// DESCRIPTION
// --ListenFirstFreePort--
//
// Creation de la premiere socket qui ecoute le premier port
// de libre
//
// ARGUMENTS
// Argument1: int * pnPort
// RETOUR/RESULTAT
// static SOCKET
// REMARQUE
// Rev 09/12/2003
//////////////////////////////////////////////////////////////////////////////
static SOCKET ListenFirstFreePort( int * pnPort )
{
struct sockaddr_in addr;
int len = sizeof(addr);
SOCKET hSocket;

// Premiere socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}

// On ecoute le premier port de libre
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = htonl (INADDR_ANY); addr.sin_port htons ((unsigned short)*pnPort ); // 0 le premier de libre
if ( bind( hSocket, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR )
{
printf( "bind() error %d\n", SOCKET_ERRNO );
exit(1);
}
if ( listen( hSocket, 100) == SOCKET_ERROR )
{
printf( "listen() error %d\n", SOCKET_ERRNO );
exit(1);
}

// On recupere la valeur du port
if( getsockname( hSocket, (struct sockaddr *)&addr, &len) == SOCKET_ERROR )
{
printf( "listen() error %d\n", SOCKET_ERRNO );
exit(1);
}
*pnPort = ntohs( addr.sin_port );

return hSocket;
}

/////////////////////////////////////////////////////////////////////////////
//
// CONNECTTOPORT
/////////////////////////////////////////////////////////////////////////////
//
// DESCRIPTION
// --ConnectToPort--
//
// Creation de la 2° socket qui va se connecter sur la premiere
//
// ARGUMENTS
// Argument1: int nPort
// RETOUR/RESULTAT
// SOCKET
// REMARQUE
// Rev 09/12/2003
//////////////////////////////////////////////////////////////////////////////
SOCKET ConnectToPort( int nPort )
{
struct sockaddr_in addr;
SOCKET hSocket;
u_long arg; int err;

// Deuxieme socket
hSocket = socket( PF_INET, SOCK_STREAM, 0 );
if( hSocket == INVALID_SOCKET )
{
printf( "socket() error %d\n", SOCKET_ERRNO );
exit(1);
}

// On passe en mode non bloquant
arg = 1;
err = ioctlsocket( hSocket, FIONBIO, &arg );
if( err == SOCKET_ERROR )
{
printf( "ioctlsocket() : Error n %d\n", SOCKET_ERRNO );
exit(1);
}

// On se connecte en local
addr.sin_family = AF_INET ;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons ((unsigned short)nPort );
if( connect( hSocket, (struct sockaddr *)&addr, sizeof(addr) ) == SOCKET_ERROR )
{
// En mode non bloquant, on aura jours l'erreur
// WSAEWOULDBLOCK qui n'en est pas une
if( SOCKET_ERRNO != WSAEWOULDBLOCK )
{
printf( "connect() error (%d)\n", SOCKET_ERRNO );
return -1;
}
}

return hSocket;
}

void main()
{
WSADATA stack_info;
SOCKET ahSocket[4];
WSAEVENT ahEvents[4];

int rc;
int nListenPort = 0;

// On initialise Winsock
WSAStartup(MAKEWORD(2,0), &stack_info) ;

// 3 evenements pour les 3 socket
ahEvents[0] = WSACreateEvent();
ahEvents[1] = WSACreateEvent();
ahEvents[2] = WSACreateEvent();

// 1 evenement d'administration (pour ajouter une socket en écoute par exemple)
ahEvents[3] = WSACreateEvent();

// Premiere socket qui ecoute
ahSocket[0] = ListenFirstFreePort( &nListenPort );
rc = WSAEventSelect(ahSocket[0], ahEvents[0], FD_ACCEPT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}

// 2° socket qui se connecte sur la premiere
ahSocket[1]= ConnectToPort(nListenPort);
rc = WSAEventSelect(ahSocket[1], ahEvents[1], FD_CONNECT );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}

// On boucle
while (TRUE)
{
DWORD dwEvent;
WSANETWORKEVENTS NetworkEvents;

// On attend que quelquechose arrive.
// Typiquement, on va commencer par recevoir la connexion
// puis ensuite, on sera notifie pour lire les donnees
dwEvent = WSAWaitForMultipleEvents(4, ahEvents, FALSE, INFINITE, FALSE);
switch (dwEvent)
{
case WSA_WAIT_FAILED:
printf("WSAEventSelect: %d\n", WSAGetLastError());
break;
case WAIT_IO_COMPLETION:
case WSA_WAIT_TIMEOUT:
break;

default:
// On deduit la socket du numero d'evenement
dwEvent -= WSA_WAIT_EVENT_0;
// => hSocket = ahSocket[dwEvent];

if (dwEvent == 3) // Event d'administration
{
WSAResetEvent(ahEvents[3]);
char szBuffer[256]; int cbBuffer, cbSend;
printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );
cbBuffer = sprintf( szBuffer, "Coucou depuis la socket %d\n", dwEvent );
cbSend = send( ahSocket[1], szBuffer, cbBuffer + 1, 0 );
if( cbSend != cbBuffer + 1 )
{
printf( "send() error %d\n", SOCKET_ERRNO );
exit(1);
}
continue;
}
else
{
WSAEnumNetworkEvents(ahSocket[dwEvent], ahEvents[dwEvent], &NetworkEvents);

if (FD_CONNECT & NetworkEvents.lNetworkEvents)
{
// La connexion est OK
printf( "FD_CONNECT ok (dwEvent=%d)\n", dwEvent );
// On va recevoir un paquet de donnee
rc = WSAEventSelect(ahSocket[dwEvent], ahEvents[dwEvent], FD_CLOSE | FD_READ );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
if (FD_CLOSE & NetworkEvents.lNetworkEvents)
{
// Seule la socket 2 va recevoir la notification de fermeture
printf( "FD_CLOSE ok (dwEvent=%d)\n", dwEvent );
printf( "press a key to exit\n" );
getch();
// On pourrait faire plus propre :-)
exit(0);
}
if (FD_READ & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbRecv;
// Seule la socket 1 s'attend a recevoir un paquet de donnees
printf( "FD_READ ok (dwEvent=%d)\n", dwEvent );

// On lit le paquet
cbRecv = recv( ahSocket[dwEvent], szBuffer, sizeof(szBuffer) - 1, 0 );
if( cbRecv <= 0 )
{
printf( "recv() error %d\n", SOCKET_ERRNO );
exit(1);
}
// On ecrit ce paquet (On remet le 0 au cas ou le paquet
// ait ete coupe en 2 - je sais, ca n'arrivera jamais en local)
szBuffer[cbRecv] = 0;
printf( "socket %d : '%s'\n", dwEvent, szBuffer );

// Maintenant on lève un event d'administration
WSASetEvent(ahEvents[3]);
}
if (FD_WRITE & NetworkEvents.lNetworkEvents)
{
char szBuffer[256]; int cbBuffer, cbSend;
// il doit s'agir de la 2° socket, puisque c'est la seule
// qui demande quand elle pourra ecrire.
// Comme on est la, c'est qu'on doit pouvoir ecrire
printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );

// On envoie la chaine avec le 0 de fin
cbBuffer = sprintf( szBuffer, "Coucou depuis la socket %d\n", dwEvent );
cbSend = send( ahSocket[dwEvent], szBuffer, cbBuffer + 1, 0 );
// En socket non bloquante, il est possible que cbSend < cbBuffer
// en particulier en charge. Il faut donc verifier cela et buffeuriser
// au cas ou. Ici, c'est un exemple donc on ne le fait pas
if( cbSend != cbBuffer + 1 )
{
printf( "send() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
if (FD_ACCEPT & NetworkEvents.lNetworkEvents)
{
struct sockaddr_in addr;
int len;
// On doit avoir dwEvent=0
printf( "accept ok (dwEvent=%d)\n", dwEvent );
len = sizeof( addr );

// On accepte la connexion (3° socket => ahSocket[2] )
ahSocket[2] = accept(ahSocket[dwEvent], (struct sockaddr *)&addr, &len);
// On demande à etre prevenu qd on pourra ecrire de la
// donnee sur cette nouvelle socket
rc = WSAEventSelect(ahSocket[2], ahEvents[2], FD_CLOSE | FD_WRITE );
if( rc == SOCKET_ERROR )
{
printf( "WSAEventSelect() error %d\n", SOCKET_ERRNO );
exit(1);
}
}
}
}
}
WSACloseEvent( ahEvents[0] );
WSACloseEvent( ahEvents[1] );
WSACloseEvent( ahEvents[2] );
}

4 réponses

Messages postés
694
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
8 janvier 2014
16
Salut



if (dwEvent == 3) // Event d'administration

{

WSAResetEvent(ahEvents[3]);

char szBuffer[256]; int cbBuffer, cbSend;

printf( "FD_WRITE ok (dwEvent=%d)\n", dwEvent );

cbBuffer = sprintf( szBuffer, "Coucou depuis la socket %d\n", dwEvent );

cbSend = send( ahSocket[2], szBuffer, cbBuffer + 1, 0 );

if( cbSend != cbBuffer + 1 )

{

printf( "send() error %d\n", SOCKET_ERRNO );

exit(1);

}

continue;

}



Apparement avec ça le paquet est bien envoyé et reçu, mais après ça boucle.

Si ça peut t'aider.
Messages postés
37
Date d'inscription
mardi 8 juillet 2003
Statut
Membre
Dernière intervention
27 avril 2006

Merci...et pourtant j'ai cherché longtemps...
Messages postés
694
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
8 janvier 2014
16
Juste une question, comme je n'ai pas trop compris ce que tu voulais faire.
Je m'attendais à voir une alternance paquet de service - paquet admin - paquet de service - paquet admin - etc... Mais en fait, la socket ne recoit que des paquets admin (sauf 1 de service). C'était ce que tu voulais ?
Messages postés
37
Date d'inscription
mardi 8 juillet 2003
Statut
Membre
Dernière intervention
27 avril 2006

En fait,

Je souhaite faitre un ordonnaceur réseau que l'on puisse interrompre pour :

1 - Ajouter une socket à scrupter
2 - Envoyer une donnée.

Je souhaite que l'interruption soit également événementielle (event d'admin) => je ne veux surtout pas d'un WaitForMultipleEvents avec timeout qui poll à chaque fois pour déterminer si une donnée doit être envoyée ou si une nouvelle socket doit être scruptée.

Le code que j'ai donné ici n'est qu'un test pour voir si il était possible de sortir du WaitForMultipleEvents autrement qu'avec un événement "réseau".

Comme tu le dis, l'objectif en définitive est bien d'avoir une alternance paquet de service (réception de données) / paquet admin (avec bcp plus de paquet de données par ailleurs).

Si tu as d'autres questions!no problem