Evènement sur un socket client

Utilisateur anonyme - 25 juil. 2003 à 12:25
 Utilisateur anonyme - 25 juil. 2003 à 17:48
J'aimerais savoir si la méthode utilisée par BlackGoddess pour son serveur (http://www.cppfrance.com/article.aspx?ID=1287) est récupérable pour gérer un client, particulièrement pour que le programme client détecte qu'il a perdu la connexion (soit par kick, soit dû à un pb réseau).

J'ai essayé avec fd_close mais ça ne marche pas (le serveur fait un closesocket() sur le socket du client).

J'avais réussi à détecter la perte du serveur avec recv(), mais je dois faire ça autrement.
Je voulais que les requètes/réponses au serveur se fassent de façon pouctuelle et séquentielle, tout en faisant détecter la perte de connexion par une thread mais à y réfléchir ça risque de poser un problème entre la thread qui détecterait le conn lost et les recv séquentiels qui peuvent aussi détecter ce conn lost.
Vais-je devoir éliminer la thread ?

Arf et à y penser le serveur doit envoyer de temps en temps des ordres aux clients, ce qui parasiterait mes recv séquentiels... un vrai casse tête, aller je vais manger ça me permettra peut-être de trouver une solution, si quelqu'un en a une, qu'il n'hésite pas à me répondre :).

Merci.

10 réponses

cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
25 juil. 2003 à 14:12
Salut,
Je comprend pas ton probleme.
Si ton serveur fait closesocket sur le socket d'un client alors le client recevra FD_CLOSE (quand ca marche ca fait ca).
Elimine ta technique avec le thraed, FD_CLOSE marche nickel.
0
Utilisateur anonyme
25 juil. 2003 à 14:50
En fait j'ai expliqué des trucs qui sont hors de mon problème, pour simplifier, je n'arrive pas à récupérer l'évènement FD_CLOSE, pourtant ce n'est pas faute de faire pareil que pour le serveur.

Je fais mon WSA create event juste avant de connecter le client au serveur (aucune erreur générée) :
this->h_ConnexionRompue = WSACreateEvent();
WSAEventSelect(this->sk_Serveur, this->h_ConnexionRompue, FD_CLOSE); // Associer l'évènement FD_CLOSE du socket à he_Accept

puis je fais mon WSA wait for multiple events dans ma thread :

WaitRes = WSAWaitForMultipleEvents(cbTabEvents, TabEvents, FALSE, WSA_INFINITE, FALSE);

Mais lorsque le serveur fait le closesocket() (qui ne renvoie pas d'erreur), la thread du client ne bronche pas.

L'évènement se crée bien, la connexion se fait bien, le serveur reçoit bien le fd_close qd le client se déconnecte, mais qd le serveur kick tout le monde ça ne génère rien chez le client :/
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
25 juil. 2003 à 15:17
Salut,
J'avais pas compris que tu utilisais WSAEventSelect désolé (perso j'utilise WSAAsyncSelect car pas de thread).
Faudrais que tu poste ton code plutot que des copies de celui de BlackGoddess. he_Accept et TabEvents sont definis nulle part dans ton bout de code.

Moi je ferai:

WSAEVENT EventClose = WSACreateEvent();
WSAEventSelect( LeSocket, EventClose, FD_CLOSE);

// ...

WSAWaitForMultipleEvents( 1, EventClose, FALSE, WSA_INFINITE, FALSE);
0
Utilisateur anonyme
25 juil. 2003 à 15:53
> J'avais pas compris que tu utilisais WSAEventSelect désolé (perso j'utilise WSAAsyncSelect car pas de thread).

C'est-à-dire que je n'ai pas changé de méthode, celle utilisée par BG me convenait parfaitement (pour mon serveur).

> Faudrais que tu poste ton code plutot que des copies de celui de BlackGoddess. he_Accept et TabEvents sont definis nulle part dans ton bout de code.

Les copies viennent de mon code, je ne me suis pas amusé à renommer les variables temporaires telles que le tableau et sa taille, d'où le fait que la 3ième ligne que j'ai mise soit strictement identique au code de BG. Par contre comme je suis sur le client j'ai fait sauter le he_Accept et les he_clients, mon tableau fait seulement 2 events actuellement (le 2nd étant l'event pour fermer la thread).

Je n'ai pas mis le code parce qu'il est long, je vais essayer de mettre ça dans un message suivant celui-ci.

En regardant avec QuickWatch je me suis aperçu qu'en sortant de la thread ma liste de clients (côté serveur donc) perd des infos (les infos en char*, à savoir l'ip et le nom de machine), c'est un autre pb pour sûr mais le nom réseau de machine sous Windows est limité à combien de caractères ?

> WSAEVENT EventClose = WSACreateEvent();
> WSAEventSelect(LeSocket, EventClose, FD_CLOSE);
>
> // ...
>
> WSAWaitForMultipleEvents( 1, EventClose, FALSE, WSA_INFINITE, FALSE);

erf, le problème c'est qu'il y a le second évènement à gérer (pour quitter la thread) (toujours avec la méthode BG).
0

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

Posez votre question
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
25 juil. 2003 à 16:03
Salut,
Essaye deja de faire fonctionner un event FD_CLOSE comme tu le souhaites avant d'essayer d'en gerer plusieurs.

Apres quand tu aura reussi, tu pourra mettre tout les events dans une tableau et passer le tableau en 2eme argument a WSAWaitForMultipleEvents (comme le fait BG).

Pour le probleme du nom reseau dans windows, désolé j'en ai aucune idée.
0
Utilisateur anonyme
25 juil. 2003 à 16:04
Voilà le code côté client, je rechigne à mettre beaucoup de code parce qu'en général ça rebute.

// Ma fonction qui connecte le client au serveur
bool CNetworkClient::ConnecterClient(char *ServeurIP, int ServeurPort)
{
this->h_GererClient = NULL;

// Initialisation des évènements
this->h_DeconnecterClient = CreateEvent(NULL, FALSE, FALSE, NULL);
this->h_ConnexionRompue = WSACreateEvent();
WSAEventSelect(this->sk_Serveur, this->h_ConnexionRompue, FD_CLOSE);

this->c_ServeurIP = ServeurIP;
this->i_ServeurPort = ServeurPort;

// SI le client est déjà démarré ALORS ne rien faire
if ( this->dw_EtatClient == CLIENTETAT_CONNECTE ) return false;

// SINON le démarrer
// Initialiser le socket de communication avec le(s) serveur(s)
SOCKADDR_IN sin;

sin.sin_addr.s_addr = inet_addr(c_ServeurIP);
sin.sin_family = AF_INET;
sin.sin_port = htons(i_ServeurPort);
this->sk_Serveur = socket(AF_INET,SOCK_STREAM,0);
bind(this->sk_Serveur, (SOCKADDR *)&sin, sizeof(sin));

// Tant que l'on est pas connecté au serveur, tenter la connection
while ( connect(this->sk_Serveur, (SOCKADDR *)&sin, sizeof(sin)) )
{
if ( MessageBox(NULL, "Impossible d'etablir la connection.\n\nVoulez-vous réessayer ?", dWinMSG_Client_Title, MB_RETRYCANCEL) == IDCANCEL)
return false;
}
this->Afficher("Vous êtes connecté.");

this->GererClient();
this->SetEtatClient(CLIENTETAT_CONNECTE);

return true;
}

// Ma thread de gestion du socket vers le serveur
DWORD CNetworkClient::GERER_CLIENT(CNetworkClient *Client)
{
HANDLE* TabEvents;
int cbTabEvents;
DWORD WaitRes;

bool StopperClient = false;
while(!StopperClient)
{
// Construction du tableau des évènements à gérer
cbTabEvents = 2;
TabEvents = new HANDLE[cbTabEvents];

TabEvents[0] = Client->h_DeconnecterClient;
TabEvents[1] = Client->h_ConnexionRompue;

WaitRes = WSAWaitForMultipleEvents(cbTabEvents, TabEvents, FALSE, WSA_INFINITE, FALSE);

delete[] TabEvents;

switch(WaitRes)
{
case WSA_WAIT_EVENT_0:
{
StopperClient = true;
}
break;

case WSA_WAIT_EVENT_0+1:
{
Client->Afficher("EVENEMENT : Connexion avec le serveur rompue.");
}
break;
} // switch
} // while

return 0;
}

// A noter que je sais que toutes les erreurs ne sont ici pas gérées mais ça va venir (pour mon problème j'ai vérifié, aucune erreur générée)
0
Utilisateur anonyme
25 juil. 2003 à 16:28
> WSAWaitForMultipleEvents( 1, EventClose, FALSE, WSA_INFINITE, FALSE);

Décidément :

"
error C2664: 'WSAWaitForMultipleEvents' : cannot convert parameter 2 from 'void *' to 'void *const * '
"
0
Utilisateur anonyme
25 juil. 2003 à 16:31
erf, je ne peux pas éditer mon message.

J'ai le cerveau en boulette, suffit bien sûr de mettre un & pour le EventClose.

Ca fait pareil, il ne détecte pas l'évènement.
0
Utilisateur anonyme
25 juil. 2003 à 17:23
Bon et bien j'ai placé un send() sur le serveur et un recv() sur le client (juste après la création de la thread), la coupure serveur ainsi que le message envoyé par le send() sont détectés par le recv() mais pas par le WSAWaitxx de la thread.

J'ai trouvé une bouteille d'alcool dans le PC... j'en ai bu aussi, du coup je vais mettre un recv() dans ma thread et un case derrière, ça risque de m'handicaper mais je n'ai pas trop le choix, je ne peux pas me permettre de rester bloqué encore plus de temps.
0
Utilisateur anonyme
25 juil. 2003 à 17:48
Merci à aardman qui a résolu mon problème, dans mon code il a remarqué que l'initialisation de l'evènement sur le socket est fait AVANT l'initialisation du socket, grosse erreur, il faut bien sûr la faire après !

Merci encore :)
0
Rejoignez-nous