Problème lors de la fermeture de sockets

malik7934 Messages postés 1154 Date d'inscription mardi 9 septembre 2003 Statut Membre Dernière intervention 15 août 2009 - 15 sept. 2004 à 17:38
cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 - 17 sept. 2004 à 18:19
Hello,

J'ai dans mon programme un socket qui est ouvert et j'envoie d'un client vers un serveur (et vice versa) des infos qui sont traîtées à chaque fois. Si suite à un traitement je'ai pour réponse FALSE, alors un message d'erreur apparaît et le programme est arrêté (j'ai mis à chaque fois {closesocket(m_socket); return FALSE;} en cas d'erreur).

Mon problème: si je veux re-exécuter mon programme avec d'autres données (fichier extérieur), je dois d'abord fermer mon programme, sinon il plante systématiquement. Je suis pratiquement certain que c'est une question de mauvaise fermeture de sockets, pourtant j'ai mis des closesocket à outrance dans tous les coins! Une idée?

HELP!!!

Thanx, Malik7934

10 réponses

cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 2
15 sept. 2004 à 18:38
Tu recrées le socket après l'avoir fermé ou pas ? Parce qu'une fois fermé, le socket est inutilisable...
0
malik7934 Messages postés 1154 Date d'inscription mardi 9 septembre 2003 Statut Membre Dernière intervention 15 août 2009 17
15 sept. 2004 à 19:34
En deux mots, j'ai une fonction ServerListen. Lorsqu'elle est lancée, si j'exécute ClientConnect, une connexion est crée. Ca veut dire un socket. Ca, je le fais au début de mon prog, ensuite j'utilise des fonctions "maison" genre sendfile(name) ou receivefile(name). Lors du traîtement, avant de faire, si besoin, un return FALSE, je fais closesocket(m_socket) systématiquement... et normalement, si je relance le tout (sans fermer le programme donc), je devrais retomber sur ClientConnect et un nouveau socket devrait être créé... mais dès lors, ça plante (soit le prog ne voit pas la nouvelle socket, soit il agit comme si l'ancienne était tjs là, ce qui n'est pas le cas).

En fait, je me demandais surtout s'il y a une systématique pour la fermeture des sockets? Comme on le fait toujours avec un fichier texte (cf closehandle).

J'suis plus clair là?
0
cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 2
15 sept. 2004 à 20:09
Pas vraiment plus clair...

Un socket doit être fermé quand tu n'en as plus besoin (généralement à la déconnexion d'un client, un seul closesocket suffit), pas après chaque opération... Çà vient peut-être d'une erreur dans la manière dont tu passes le handle du nouveau socket à ClientConnect, ou de la manière dont tu as géré les déconnexions, ou de n'importe quoi d'autre, je ne sais pas :-/

Enfin sans code, c'est difficile à déterminer...
0
malik7934 Messages postés 1154 Date d'inscription mardi 9 septembre 2003 Statut Membre Dernière intervention 15 août 2009 17
15 sept. 2004 à 20:55
ok, je regarderai demain si j'arrive à mettre du code explicite (mon code fait passé 1000 lignes, alors je peux pas tout mettre comme ça),

thanx, Malik7934
0

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

Posez votre question
malik7934 Messages postés 1154 Date d'inscription mardi 9 septembre 2003 Statut Membre Dernière intervention 15 août 2009 17
16 sept. 2004 à 08:38
Hello,

me revoilà avec du code cette fois!

Au départ, j'ai un serveur qui se met en écoute si on appuie sur le bouton "LISTEN":
case IDC_LISTEN:
  char tBuff[6];
  int PORT;
  GetDlgItemText(hWndconfp,IDC_PORT,tBuff,5);
  PORT = atoi(tBuff);
  ServerListen(PORT);

La fonction ServerListen est des plus standard: Initialisation de WINSOCK, création du socket, binding du socket et écoute sur le socket.

Ensuite, un client vient se connecter (même blabla: Initialisation de WINSOCK, création du socket, connection au serveur).

Ensuite, je commence à avoir des problème: je fais des échanges de fichiers avec des fonctions genre
if (!csSendFile("C:/WINDOWS/Temp/hello.txt")) {closesocket(m_socket);return FALSE;}

et tout va très bien s'il n'y a pas d'erreur (à chaque étape, des traîtements ont lieu et retournent True ou False). Par contre, s'il y a un False, mon prog plante! Ca veut dire qu'en cas d'erreur, il est interrompu et si je le re-exécute sans le fermer et l'ouvrir à nouveau, il ne fonctionnera plus. Sûr que c'est une histoire de fermetur/ouverture de socket...
0
cs_aardman Messages postés 1905 Date d'inscription mercredi 22 janvier 2003 Statut Membre Dernière intervention 17 septembre 2012 3
16 sept. 2004 à 11:16
Salut,
Si tu fermes ton socket avec closesocket() le status du port va etre WAIT (TIME-WAIT ou CLOSE-WAIT) car le socket n'a pas été fermé proprement. Au bout de quelques minutes le port perd ce status et peut etre réutilisé (Tu peux faire un netstat pour le voir par toi meme).
Normalement on utilise shutdown() suivit de closesocket() pour fermer une connexion proprement.

Regarde du coté de setsockopt() avec l'option SO_REUSEADDR, qui permet de re-binder sur un port sans avoir a attendre plusieurs minutes.
0
cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 2
16 sept. 2004 à 13:26
> La fonction ServerListen est des plus standard: Initialisation de WINSOCK, création du socket, binding du socket et écoute sur le socket.

> Ensuite, un client vient se connecter (même blabla: Initialisation de WINSOCK, création du socket, connection au serveur).

Si je te suis tu initialises Winsock plusieurs fois dans l'appli... Il vaut mieux éviter à moins que tu ne le fasses dans différents threads.

Sinon y'a rien de suspect dans ton code à part le manque de shutdown pointé par aardman, c'est peut être dans ton imbrication de return qu'à un moment y'a un truc qui va pas...

Et j'ai un doute en relisant, tu appelles WSACleanup plusieurs fois aussi ? Car un seul appel suffit pour que tous les sockets du thread courant soient inutilisables...
0
malik7934 Messages postés 1154 Date d'inscription mardi 9 septembre 2003 Statut Membre Dernière intervention 15 août 2009 17
17 sept. 2004 à 11:29
Hello!

Je te mets mon code (c'est un patchwork de sources trouvées ici, j'avoue avoir pas trop pigé).

D'abord les fonctions:
#include <winsock2.h>		// Socket 
#pragma comment(lib,"WS2_32.lib") // Librairie Associé au Socket

#define WM_SOCKET	WM_USER+100
int ClientConnect(char *IP,int PORT);
SOCKET m_socket;
SOCKET AcceptSocket;
sockaddr_in clientService;
//BOOL csGet();
//BOOL csSend();

// ###############################################################
// *********** 
// *********** Connection du client
// *********** 
// ###############################################################

BOOL ClientConnect(char *IP,int PORT)
{
// Initialize Winsock.
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != NO_ERROR)
{
     
WSACleanup(); return FALSE;

}

//Create a socket.
    m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    if (m_socket == INVALID_SOCKET) 
{  
WSACleanup(); return FALSE;
    }

// Connect to a server.
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr(IP);
    clientService.sin_port = htons(PORT);

    if (connect(m_socket,(SOCKADDR*) &clientService,sizeof(clientService)) == SOCKET_ERROR) 
{
        WSACleanup();
return FALSE;
    }
else
{
return TRUE;
}

//Initialisation de WSAAsyncSelect
if(WSAAsyncSelect(m_socket, NULL, WM_SOCKET, FD_READ|FD_WRITE|FD_CONNECT) == SOCKET_ERROR)
{
WSACleanup(); return FALSE;
}

return TRUE;
}

// ###############################################################
// *********** 
// *********** Envoi d'un char
// *********** 
// ###############################################################

BOOL csSend(char* szData, DWORD msgSize)
{
send(m_socket,szData,msgSize,0);
return TRUE;
}

// ###############################################################
// *********** 
// *********** Envoi d'un fichier
// *********** 
// ###############################################################

BOOL csSendFile(char* fileName)
{
FILE* fich;
char *buffer;
int TailleFichier1;
DWORD dwFileSize=0;
HANDLE hSrcFile = INVALID_HANDLE_VALUE;

hSrcFile = CreateFile(fileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(hSrcFile == INVALID_HANDLE_VALUE)
{
CloseHandle(hSrcFile);
return FALSE;
}

dwFileSize = GetFileSize(hSrcFile,NULL) + 1;
CloseHandle(hSrcFile);

if ((buffer=(char *)malloc(dwFileSize))==NULL) return FALSE;
if ((fich=fopen(fileName,"rb"))==NULL) return FALSE;

    TailleFichier1=fread(buffer,1,10000,fich);
    if (send(m_socket,buffer,TailleFichier1,0)<0) return FALSE;
    fclose(fich);
free(buffer);

return TRUE;
}

// ###############################################################
// *********** 
// *********** Réception d'un buffer 
// *********** 
// ###############################################################

BOOL csGet(char* getData)
{
ZeroMemory(getData,10000);
recv(m_socket,getData,10000,0);
return true;
}

// ###############################################################
// *********** 
// *********** Réception d'un fichier
// *********** 
// ###############################################################

BOOL csGetFile(char* fileName)
{
FILE* fich;
char *buffer;			// buffer memoire, va recevoir données du serveur
int TailleFichier;		// Taille Fichier

if ((fich=fopen(fileName,"w"))==NULL) {return FALSE;}
    if ((buffer=(char *)malloc(10000))==NULL) {return FALSE;}
if ((TailleFichier=recv(m_socket,buffer,10000,0))<0) {return FALSE;}
fwrite(buffer,1,TailleFichier,fich);	// Ecriture dans FICHIER
fclose(fich);
free(buffer);			// Libère mémoire

return TRUE;
}

// ###############################################################
// *********** 
// *********** Attente d'un client
// *********** 
// ###############################################################

BOOL ServerListen(int PORT)
{
//Initialisation de WINSOCK
WSADATA wsaData;

//int optval = 0x200;

int iResult = WSAStartup(MAKEWORD(2,2),&wsaData);
if(iResult != NO_ERROR)
{
WSACleanup();
return FALSE;
}

//Creation du socket
m_socket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(m_socket == INVALID_SOCKET)
{
WSACleanup();
return FALSE;
}

//Binding du socket
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.S_un.S_addr = INADDR_ANY;
service.sin_port = htons(PORT);

iResult = bind(m_socket,(SOCKADDR*) &service, sizeof(service));
if(iResult == SOCKET_ERROR)
{
closesocket(m_socket);
return FALSE;
}

//Ecoute sur le socket
if (listen(m_socket,0) == SOCKET_ERROR) // J'ai remplacé le 0 par un 1

//	setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&optval, sizeof(optval));
//	setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO, (char*)&optval, sizeof(optval));

if(WSAAsyncSelect(m_socket, NULL, WM_SOCKET, FD_ACCEPT|FD_CLOSE|FD_READ|FD_WRITE) == SOCKET_ERROR)
{
WSACleanup();
return FALSE;
}

return TRUE;
}


Dans mon prog, je n'ai qu'un seul client, du coup il me semble qu'il ne vient se connecter qu'une fois (ClientConnect(..))

Ensuite, dans mon programme principale, je fais des appels genre:
if (!csSendFile("file.txt")) {return FALSE;}


et le "return false" me fait sortir de la où je suis et m'envoie à
...
case IDC_COMP:
if(computeS(hWndconf)){
MessageBox(hWndconf,"GHIProof successfully executed","Verifier: Success",MB_OK);
}
else{
MessageBox(hWndconf,"GHIProof aborted: an error occurs","Verifier: Error",MB_OK);
}
closesocket(m_socket);
return TRUE;


En fait, que ce soit True ou False, lorsque j'en ai fini avec mon client (computeS), mon socket est fermé!

Tu penses quoi de mon code (faut encore que je tienne compte de la remarque de aardman) ???
0
cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 2
17 sept. 2004 à 18:17
Pas de boucle dans ServerListen, elle ne peut donc servir qu'une fois...

Pourquoi tous ces WSAStartup() ? Appelle le dans WinMain() ou main(), mais pas à chaque fois que tu as envie d'utiliser un socket ! Même remarque pour WSACLeanup, à partir d'un seul appel tous les sockets du programme sont détruits => ne l'appelle qu'avant de sortir du programme.

if(hSrcFile == INVALID_HANDLE_VALUE)
{
CloseHandle(hSrcFile);
return FALSE;
}
=> Inutile de fermer un handle invalide !

Sinon, pour en finir et sans vouloir être mesquin, çà se voit que c'est un patchwork de source... C'est assez décousu ! Regarde donc à cette adresse, et fais ton propre code (c'est plus facile pour commencer, que de reprendre des codes existants) : http://c.developpez.com/WalrusSock/

Y'a sûrement d'autres erreurs, j'ai juste survolé... Bon courage !
0
cs_Nebula Messages postés 787 Date d'inscription samedi 8 juin 2002 Statut Membre Dernière intervention 7 juin 2007 2
17 sept. 2004 à 18:19
Ah, j'oubliais : concernant la remarque d'aardman, la norme stipule une manière de fermer proprement un socket, et sous windows c'est :

shutdown(socket, SD_BOTH);
closesocket(socket);

Donc, oui ;-)
0