problème de socket client --> bloquantes ou pas

problème de socket client --> bloquantes ou pas - C++ - Programmation

Marsh Posté le 15-01-2004 à 16:20:14    

Hello,
 
Voici le problème.  
 
Je travaille sur un client socket pour POP. Lorsque je send le message (par exemple "USER jagstang" )
 
je récupère tout de suite après la réponse avec recv()
 
Il arrive que le serveur ne soit pas assez prompt pour la réponse, et le buffer est vide...
 
J'ai pas trop l'envie de mettre des sleep ou autres...
 
J'ai lu pas mal de trucs à ce sujet, notamment l'utilisation de socket bloquantes / non bloquantes, ainsi que de faire un thread pour chaque envoi/réponse
 
Quelqu'un a-t-il une idée ?
 
Merci

Reply

Marsh Posté le 15-01-2004 à 16:20:14   

Reply

Marsh Posté le 15-01-2004 à 16:22:45    

apparement si le buffer de recv est vide, c'est que ton socket n'est pas bloquant ou que la connexion a été coupée.
sinon, pour attendre l'arrivée de données, tu peux jouer avec select() de l'api socket


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 15-01-2004 à 17:29:10    

select ne change malheureusement rien....

Reply

Marsh Posté le 15-01-2004 à 17:30:34    

donne un bout de code pour voir ? du moment ou tu crée ton socket jusqu'au recv qui foire ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 15-01-2004 à 17:31:48    

ben c pas bloquant par defaut ? comment se fesse que tu sois en non-bloquant ?

Reply

Marsh Posté le 15-01-2004 à 18:25:54    

Je t'invite à faire afficher la valeur retournée par recv() lorsque ce dernier se "débloque" sans retourner un seul octet de données.
 
En effet, recv() retourne 0 lorsque la connexion a été interrompue correctement independament de ta volonté. recv() retourne -1 (SOCKET_ERROR) lorsque la connexion a été interrompue de manière inatendue (genre "connection reset by peer" ).
 
Perso, j'ai un soucis du même genre avec un retour d'erreur égale à 183 (ca ne semble meme pas etre une erreur de type socket mais une erreur plus générale)... cela dit pas d'etonnement dans tous les cas, il y a visiblement bcp de raison pour qu'une connexion TCP se déconnecte toute seule ! :)
 
Cordialement,  
   Xter.

Reply

Marsh Posté le 17-01-2004 à 15:12:22    

voilà.
 
création socket

Code :
  1. bool DahuSocks::Connect(const string &ip, const unsigned int port)
  2.     {
  3.     sin.sin_addr.s_addr = inet_addr(ip.c_str());
  4.     sin.sin_family  = AF_INET;
  5.     sin.sin_port  = htons(port);
  6.     sock = socket(AF_INET,SOCK_STREAM,0);
  7.     if (connect(sock, (SOCKADDR *)&sin, sizeof(sin)) != SOCKET_ERROR)
  8.         isConnected = true ;
  9.     // socket option
  10.     int on = 1 ;
  11.     if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 )
  12.         isConnected = false;
  13.     /*int buffSize = BUFFERSIZE ;
  14.     if (setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (const char *) &buffSize, sizeof (buffSize) ) == -1 )
  15.         isConnected = false;
  16.     */
  17.     // bind
  18.     //if (bind(sock, (SOCKADDR *)&sin, sizeof(sin)) != SOCKET_ERROR)
  19.     //    cout << "erreur bind" ;
  20.     // maximum time to wait
  21.     fd_set a ;
  22.     a.fd_array[0] = sock ;
  23.     a.fd_count = 1 ;
  24.     timeval b ;
  25.     b.tv_sec = 2 ;
  26.     b.tv_usec = 200 ;
  27.     select(0, &a, &a, &a, &b) ;
  28.     // socket non bloquante
  29.     /*u_long argp=1;
  30.     ioctlsocket(sock, FIONBIO, &argp) ;
  31.     if (argp == 0)
  32.       return false ;
  33.     */
  34.     return isConnected ;
  35.     }[code]
  36. string DahuSocks::Recv(bool multiline)
  37.     {
  38.     char mbuffer [BUFFERSIZE+1] ;
  39.     string sbuffer="" ;
  40.     int errcode=0 ;
  41.     int i=0 ;
  42.     long downloaded=0 ;
  43.     char bspace[] = {8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0 } ;
  44.     char wait[] = {'|', '/', '-', '\\'} ;
  45.     do
  46.         {
  47.         WSASetLastError(0) ;
  48.         memset(mbuffer, 0, BUFFERSIZE) ;
  49.         errcode = recv(sock, mbuffer, BUFFERSIZE, 0) ;
  50.         sbuffer.append(mbuffer) ;
  51.         #ifdef DEBUG
  52.         //cout << "\nWSA :" << WSAGetLastError() ;
  53.         //cout << "\nerrcode : " << errcode ;
  54.         #endif
  55.         downloaded += errcode ;
  56.         if (i++>0)
  57.             cout << bspace << wait[i%4] << " " << downloaded << " bytes" ;
  58.         }
  59.     while (errcode == BUFFERSIZE && WSAGetLastError()==0) ;
  60.     if (i>1)
  61.         {
  62.         cout << bspace ;
  63.         cout << downloaded << " bytes OK" ;
  64.         }
  65.     return sbuffer ;
  66.     }


 
le problèmest est que parfois le buffer n'est pas plein. Donc la boucle s'arrête est le message est tronqué
 
Je précise que j'utilise ceci pour récupérer un mail sur un serveur POP.


Message édité par jagstang le 17-01-2004 à 15:23:36
Reply

Marsh Posté le 17-01-2004 à 15:15:42    

Je comprends pas le problèmes, Sous linux sans ces WSA ça fonctionne très bien. Mais l'adaptation sous Windows est plus difficile que je pensais.


Message édité par jagstang le 18-01-2004 à 01:06:46
Reply

Marsh Posté le 18-01-2004 à 18:34:55    

:bounce:  :cry:

Reply

Marsh Posté le 20-01-2004 à 21:10:31    

Franchement, il n'a vraiment pas l'air assez robuste ton code, vis a vis des exceptions (ie.: en cas d'erreur de retour de l'appel recv() en particulier).
 
Courage,
   Xter.

Reply

Marsh Posté le 20-01-2004 à 21:10:31   

Reply

Marsh Posté le 20-01-2004 à 21:15:32    

lol. j'ai bien remarqué merci. Mais avant de gérer les exceptions, j'aimerai bien que ça fonctionne dans une utilisation normale...
 
Sinon, t'as pas une idée ?

Reply

Marsh Posté le 21-01-2004 à 12:35:43    

Remplace

Code :
  1. while (errcode == BUFFERSIZE && WSAGetLastError()==0) ;


par

Code :
  1. while( errcode > 0 );


 
 
Et compile ton code en definissant ton preprocesseur DEBUG et ajoute un max de messages pour superviser l'etat des variables. Puis post les messages de debug ici.
 
Cordialement,
   Xter.


Message édité par xterminhate le 21-01-2004 à 23:27:15
Reply

Marsh Posté le 21-01-2004 à 13:05:48    

je ne peux pas faire errcode > 0. Car comme les sockets étant bloquantes, un recv de trop me bloque l'application (qui attend...)
 
Merci pour ton aide en tout cas

Reply

Marsh Posté le 21-01-2004 à 23:26:12    

Pffff... tu as essayé au moins ?


Message édité par xterminhate le 21-01-2004 à 23:28:02
Reply

Marsh Posté le 21-01-2004 à 23:40:19    

Oui merci j'ai essayé bien avant de poster sur ce forum...

Reply

Marsh Posté le 22-01-2004 à 20:32:58    

Tu devrais adopter une gestion de socket plus avancée avec un appel selec() avant recv() et close().
 
Cordialement,
   Xter.

Reply

Marsh Posté le 23-01-2004 à 15:21:40    

dans quel but ? le problème vient-il de là ?
 
Excuse-moi mais gestion de socket plus avancée techniquement ça m'aide pas beaucoup...

Reply

Marsh Posté le 23-01-2004 à 18:00:25    

un petit exemple :
 

Code :
  1. std::string receive (const timeval* timeout, SOCKET & s) // ou const SOCKET & s, je suis plus sûr du prototype des API utilisées)
  2. {
  3.   fd_set fds;
  4.   FD_ZERO(&fds);
  5.   FD_SET(s, &fds);
  6.   unsigned long cbdata;
  7.   int cbopt = sizeof(cbdata);
  8.   if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&cbdata), &cbopt) == SOCKET_ERROR /* -1 */) { /* erreur */ }
  9.   char* data = new char[cbdata];
  10.   std::string ret; 
  11.   int select_ret; 
  12.   while((select_ret = select(0, &fds, NULL, NULL, timeout)) > 0))
  13.   {
  14.     if(FD_ISSET(s, &fds))
  15.     {
  16.       int len = recv(s, data, cbdata, 0);
  17.       if(len == SOCKET_ERROR /* -1 */) { /* erreur */ }
  18.       ret.append(std::string(data, len));
  19.     }
  20.   }
  21.   delete[] data; 
  22.   if(select_ret == SOCKET_ERROR) // -1 sous *nix
  23.   {
  24.     // il y a eu une erreur
  25.   } else {
  26.     // tout s'est déroulé correctement
  27.   }
  28.   return ret;
  29. }


 
c'est un peu codé "à la gros porc" c'est juste pour te donner une idée : le but ici est d'attendre et de recevoir jusqu'à ce que le serveur n'envoit plus rien pendant le temps 'timeout'.


Message édité par blackgoddess le 23-01-2004 à 18:03:00
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed