Salut a tous!
Voila j'ai un jeu en reseau.
Dans ce jeu, j'ai 2 threads qui ouvre des connexions TCP :
- Un qui ne fait que des boucles avec un recv pour recevoir la position du client.
- L'autre qui ne fait que des boucles avec un send pour envoyer sa position à l'autre.
Ce que j'aimerai faire, c'est que quand quelqu'un ferme sa fenetre, ou en fin de partie, bref quand on veut terminer le jeu, cela me ferme proprement :
- le socket de reception de mon PC
- le socket d'envoi de mon PC
- le socket de reception du PC distant
- le socket d'envoi du PC distant.
Pour cela dans la structure envoyée a mon thread (et échangée sur le réseau) j'ai intégré une variable "ActiverTransmission".
Quand je veux fermer la connexion, mon application principale fait passer cette variable à 0.
Ce qui a pour effet, dans mon thread d'emission, d'envoyer un shutdown de la connexion dans les 2 sens.
La variable recevant le code d'erreur du shutdown s'appelle ActiverBoucle, et elle passe a 0 quand le shutdown reussi, ce qui a donc en plus pour effet de sortir de ma boucle de transmission, et de passer au reste du code pour fermer proprement la socket.
Le problème :
Sur mon PC j'ouvre mon application une premiere fois afin de simuler un joueur. Je l'appelle "hebergeur"
J'ouvre une deuxieme fois une copie de mon application (la meme mais configurée specialement pour se connecter à la premiere) je l'appelle "client"
Lorsque je ferme mon "client", j'ai une erreur qui apparait sur mon "hebergeur" :
Impossible de recevoir les données (donc du a mon recv) avec le code d'erreur WSA 10054 qui signifie WSAECONNRESET (10054) Connection reset by peer.
Bizarre, car mon client a donc envoyé un shutdown qui a visiblement mal été interprété par mon "hebergeur"
Pouvez vous m'aider ???
Voici le code :
La structure envoyée a mon thread :
Mon thread de reception :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 typedef struct StructSocket { SDL_Rect PositionJoueur; char IPUtilisee[16]; char PortUtilise[6]; SOCKET IDSocketServeur; SOCKET IDSocketClient; BOOL ActiverTransmission; } StructSocket;
Mon thread d'envoi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 DWORD WINAPI ThreadReception(void * infRecpt) // Avec un thread on a un type void * (on peut mettre ce qu'on veut) { StructSocket * SocketReception = infRecpt; // On indique qu'on veut travailler sur une structure InfosPartie pour notre variable e/s StructSocket VarTempReception; int CodeErreur; // Code d'erreur des fonctions int TailleConfigClient; int PortEcoute; char TexteErreur[120]; // Pour insérer le message d'erreur des socket dans la msgbox int LongueurMessage=1; // Nombre de caracteres SOCKADDR_IN ConfigServeur,ConfigClient; // Structure contenant les infos du serveur SocketReception->IDSocketServeur = socket(AF_INET,SOCK_STREAM,0); // On ouvre la socket en UDP if (SocketReception->IDSocketServeur == INVALID_SOCKET) { sprintf(TexteErreur,"Impossible de creer la socket du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; // On termine la fonction et renvoi -1 pour prevenir l'appli principale } /* Config Infos Serveur */ ConfigServeur.sin_family = AF_INET; ConfigServeur.sin_addr.s_addr = inet_addr(SocketReception->IPUtilisee); sscanf(SocketReception->PortUtilise, "%d", &PortEcoute); // On reconverti notre port de char vers int #ifdef _UTILISATIONLOCALE_ #if TYPEJOUEUR == 1 ConfigServeur.sin_port = htons(2222); #else ConfigServeur.sin_port = htons(2223); #endif #else ConfigServeur.sin_port = htons(PortEcoute); #endif /* ******************* */ CodeErreur = bind(SocketReception->IDSocketServeur,(struct sockaddr*)&ConfigServeur,sizeof(ConfigServeur)); // On bind la socket if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible de binder la socket du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; } CodeErreur = listen(SocketReception->IDSocketServeur, 1); if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible d'écouter la socket du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); closesocket(SocketReception->IDSocketServeur); return -1; } TailleConfigClient = sizeof(ConfigClient); SocketReception->IDSocketClient = accept(SocketReception->IDSocketServeur, (struct sockaddr*)&ConfigClient, &TailleConfigClient); if (SocketReception->IDSocketClient == INVALID_SOCKET) { sprintf(TexteErreur,"Impossible de recuperer la socket client du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); closesocket(SocketReception->IDSocketServeur); return -1; // On termine la fonction et renvoi -1 pour prevenir l'appli principale } do { LongueurMessage = recv(SocketReception->IDSocketClient, (char*)&VarTempReception, sizeof(StructSocket),0); // On recoit et on reboucle if (LongueurMessage == SOCKET_ERROR) { sprintf(TexteErreur,"c: Impossible de recevoir les données du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); closesocket(SocketReception->IDSocketServeur); closesocket(SocketReception->IDSocketClient); return -1; } SocketReception->PositionJoueur = VarTempReception.PositionJoueur; } while (LongueurMessage != 0); // LongueurMessage vaut 0 si on recoit un shutdown, on ferme donc proprement les sockets apres. CodeErreur = closesocket(SocketReception->IDSocketServeur); // On ferme la socket qui a été ouverte if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible de libérer la socket serveur du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; } CodeErreur = closesocket(SocketReception->IDSocketClient); // On ferme la socket qui a été ouverte if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible de libérer la socket client du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; } return 0; }
Merci d'avance a ceux qui pourront m'aider!!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 DWORD WINAPI ThreadTransmission(void * infTrans) // Avec un thread on a un type void * (on peut mettre ce qu'on veut) { StructSocket * SocketTransmission = infTrans; // On indique qu'on veut travailler sur une structure InfosPartie pour notre variable e/s int CodeErreur; // Code d'erreur des fonctions int TailleConfigClient; int PortEcoute; int ActiverBoucle=1; // Cette variable passe à 0 lors d'un shutdown char TexteErreur[120]; // Pour insérer le message d'erreur des socket dans la msgbox int LongueurMessage; // Nombre de caracteres SOCKADDR_IN ConfigServeur,ConfigClient; // Structure contenant les infos du serveur SDL_Rect PositionJLocalPrecedente; SocketTransmission->IDSocketServeur = socket(AF_INET,SOCK_STREAM,0); // On ouvre la socket en UDP if (SocketTransmission->IDSocketServeur == INVALID_SOCKET) { sprintf(TexteErreur,"Impossible de creer la socket du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; // On termine la fonction et renvoi -1 pour prevenir l'appli principale } /* Config Infos Serveur */ ConfigServeur.sin_family = AF_INET; ConfigServeur.sin_addr.s_addr = inet_addr(SocketTransmission->IPUtilisee); sscanf(SocketTransmission->PortUtilise, "%d", &PortEcoute); // On reconverti notre port en char vers int #ifdef _UTILISATIONLOCALE_ #if TYPEJOUEUR == 1 ConfigServeur.sin_port = htons(2223); #else ConfigServeur.sin_port = htons(2222); #endif #else ConfigServeur.sin_port = htons(PortEcoute); #endif /* ******************* */ CodeErreur = connect(SocketTransmission->IDSocketServeur, (struct sockaddr*)&ConfigServeur, sizeof(ConfigServeur)); if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible de se connecter au serveur du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); closesocket(SocketTransmission->IDSocketServeur); return -1; } while(ActiverBoucle) // tant que telle varaible shtdown vaut 1 { if((SocketTransmission->PositionJoueur.x != PositionJLocalPrecedente.x) || (SocketTransmission->PositionJoueur.y != PositionJLocalPrecedente.y)) { LongueurMessage = send(SocketTransmission->IDSocketServeur, (char*)SocketTransmission, sizeof(StructSocket),0); if (LongueurMessage == SOCKET_ERROR) { sprintf(TexteErreur,"Impossible d'envoyer les données du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; } PositionJLocalPrecedente.x = SocketTransmission->PositionJoueur.x; PositionJLocalPrecedente.y = SocketTransmission->PositionJoueur.y; } if(!SocketTransmission->ActiverTransmission) // Si l'application demande a terminer le socket { ActiverBoucle = shutdown(SocketTransmission->IDSocketServeur, 2); // On envoi un shutdown qui ferme le client et le serveur et qui retourne 0 } SDL_Delay(30); // On fait un delay de 30ms pour diminuer l'utilisation du pross } CodeErreur = closesocket(SocketTransmission->IDSocketServeur); // On ferme la socket qui a été ouverte if (CodeErreur != 0) { sprintf(TexteErreur,"Impossible de libérer la socket serveur du à l'erreur : %d",WSAGetLastError()); MessageBox(NULL,TexteErreur,"Erreur Générale !",MB_OK | MB_ICONERROR); return -1; } return 0; }
Partager