[ Quasi-Résolu ] [socket] Effectuer deux echanges sans deconnexion

Effectuer deux echanges sans deconnexion [ Quasi-Résolu ] [socket] - C++ - Programmation

Marsh Posté le 05-07-2007 à 15:49:03    

Bonjour à tous,
 
Je suis en train de développer un serveur en C++ en utilisant les sockets qui communique avec un client en J2ME (téléphone protable).
 
Lorsque j'effectue un seul échange de données (on appelera "échange" l'envoi d'une requete depuis le téléphone suivi de la réponse du serveur) suivi d'une deconnexion, tout se passe normalement.
 
Lorsque j'en effectue deux consécutifs sans deconnexion entre les deux, les données ne sont pas recues par le client. Elles sont pourtant annoncées comme "envoyées" par le serveur (la fonction send ne bloque pas).
 
Ces données semblent donc "en attente" dans un buffer quelconque et envoyées seulement lors de la deconnexion.
 
Existe-t-il une astuce pour effectuer deux échanges sans se déconnecter ?
 
Merci.


Message édité par kabal05 le 06-07-2007 à 11:46:49
Reply

Marsh Posté le 05-07-2007 à 15:49:03   

Reply

Marsh Posté le 05-07-2007 à 17:04:54    

un flush ?
N'hésite pas à utiliser Ethereal pour voir ce qui se passe vraiment (genre t'as des concaténations de trames inattendues), et aussi à vérifier tout tes buffers au debugger.


---------------
Töp of the plöp
Reply

Marsh Posté le 05-07-2007 à 17:12:36    

_darkalt3_ a écrit :

un flush ?
N'hésite pas à utiliser Ethereal pour voir ce qui se passe vraiment (genre t'as des concaténations de trames inattendues), et aussi à vérifier tout tes buffers au debugger.


 
Dans le principe, c'est bien un flush que je veux faire mais je ne trouve pas de commande équivalente pour les sockets (j'ai oublié de préciser que j'utilisais winsock2.h).
 
Je vais voir ce que me donne ethereal.

Reply

Marsh Posté le 05-07-2007 à 17:23:14    

T'as aussi peut etre une option TCP_NODELAY qui envoie la trame direct;
sans ça, la socket attend d'etre pleine pour balancer la purée dans le reseau.


---------------
Töp of the plöp
Reply

Marsh Posté le 05-07-2007 à 17:33:06    

Oui effectivement, j'ai vu ca dans la doc et j'ai essayé :
 
erreur = setsockopt(ListeningSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&delay, sizeof(delay));
 
(ListeningSocket est ma socket et delay est un int que j'ai initialisé à 1)
 
Mais ca n'a rien changé. Soit je me suis trompé dans la facon de s'en servir (aucune erreur à l'execution, ca me renvoie 0) soit ca ne marche pas.

Reply

Marsh Posté le 05-07-2007 à 17:34:00    

A ton deuxieme envoi, le retour de send est 0 ?


---------------
Töp of the plöp
Reply

Marsh Posté le 05-07-2007 à 17:55:47    

En fait, je n'arrive pas jusqu'au deuxieme envoi. Je récapitule rapidement :
 
 1) J'envoi une requete depuis le client
 2) J'analyse la requete sur le serveur et je renvoie une donnée en conséquence
 3) je ferme tout
 
Ca, ca marche. Je recois la trame correcte sur le client.
Par contre :
 
 1) J'envoi une requete depuis le client
 2) J'analyse la requete sur le serveur et je renvoie une donnée en conséquence
 3) Le serveur me dit que la trame est envoyée (send me retourne la taille de ma trame)
 4) je ne quitte pas le serveur et j'attends une nouvelle requete du client
 5) le client ne recoit rien du tout ...
 
Si je fais un shutdown juste après l'envoi (coté serveur), je recois bien mes informations sur le client ("logique" ), mais je ne peux plus rien envoyer ("logique" aussi).
 
J'ai vraiment l'impression que la fonction send passe par un "buffer d'envoi" auquel je n'ai pas acces, et qu'elle vide ce buffer et l'envoi au client lors de la deconnexion de mon serveur...
 
Aucun message d'erreur sur le serveur, tout est normal pour lui. La fonction send me renvoie bien un code correct (longueur de trame envoyée correcte).

Reply

Marsh Posté le 06-07-2007 à 11:25:56    

(foutaise de TCP_NODELAY)
 
Je pense que tu as un problème ailleurs, le mode de fonctionnement que tu décris est tout à fait normal, tout le monde fait ça sans problème. Y a pas d'astuce. Ton client, il bloque sur son read ? tu ferais bien de stracer les deux, et de mettre un tcpdump au milieu. Ou alors si tu as du code juste pour voir ...

Reply

Marsh Posté le 06-07-2007 à 11:33:42    

J'ai résolu mon problème en envoyant à chaque fois un buffer de 1024 (char buffer[1024]) pour 100 octets maximum à envoyer, c'est pas la joie... Mais ca marche à chaque fois !!
 
La taille minimum du buffer à envoyer semble être de 800 ou un truc dans le style (mais je suis plus a 200 octets pres...).
 
Merci en tout cas pour vos réponses. Pour l'instant je m'en sors comme ca, on verra plus tard pour l'optimisation.

Reply

Marsh Posté le 06-07-2007 à 13:57:40    

TCP ? UDP ?
 
Notre copain Nagle serait-il impliqué ?

Reply

Marsh Posté le 06-07-2007 à 13:57:40   

Reply

Marsh Posté le 06-07-2007 à 14:01:00    

Je suis en TCP et j'ai bien l'impression que c'est cet enfoiré de Nagle qui m'a plombé pendant quelques jours :)

Reply

Marsh Posté le 06-07-2007 à 14:53:01    

y a pas de raison. 100 ou 1024, ça tient dans le même segment sur de l'ethernet. Nagle va attendre quelques ms avant d'envoyer. send envoie toujours sauf si on met l'option MSG_MORE, et c'est là que nagle entre en jeu. ce n'est pas nagle le problème.
 
t'as rien résolu du tout, j'attends toujours le strace/tcpdump/code etc

Reply

Marsh Posté le 06-07-2007 à 15:38:03    

Voici pour le code :  

Code :
  1. // Envoi
  2. void envoyer(SOCKET soc, char *envoi, bool *quit){
  3. int iStatus = 0;
  4. char buf[1024];
  5. strcpy(buf,envoi);
  6. iStatus = send(soc, (const char *)buf, sizeof(buf),0);
  7. cout << "Nb octets envoyes : " << iStatus << endl;
  8. if(iStatus == SOCKET_ERROR)
  9. {
  10.  cout << "send a echoue avec l'erreur : " << WSAGetLastError() << endl;
  11.  closesocket(soc);
  12.                 *quit = true;
  13. }
  14. }
  15. // Reception
  16. void recevoir(SOCKET soc, char *buffer, bool *quit){
  17. char recu[1024];
  18. int iStatus = 0;
  19. memset(recu,'\0',sizeof(recu));
  20. iStatus = recv(soc, recu, sizeof(recu), 0);
  21. if(iStatus == SOCKET_ERROR)
  22. {
  23.  cout << "recv a echoue avec l'erreur : " << WSAGetLastError() << endl;
  24.  closesocket(soc);
  25.  *quit = true;
  26. }
  27. else
  28. {
  29.  recu[iStatus] = '\0';
  30.  strcpy(buffer, recu);
  31. }
  32. }
  33. // Thread Client
  34. DWORD serveur::ClientThread(SOCKET soc){
  35. cout << "thread client demarre" << endl;
  36. char recu[1024];
  37. char envoi[1024];
  38. bool quit = false;
  39. bool REC = true;
  40. bool ENV = false;
  41. // Reception, Envoi et traitement
  42. while(!quit){
  43.  memset(recu,'\0',sizeof(recu));
  44.  memset(envoi,'\0',sizeof(envoi));
  45.  if(REC){
  46.   recevoir(soc, recu,&quit);
  47.   cout << "Recu du client : " << recu << endl;
  48.   traitement(&quit,&REC,&ENV,recu,envoi);
  49.  }
  50.  if(ENV){
  51.   envoyer(soc,envoi,&quit);
  52.   cout << "Envoye au client : " << envoi << endl;
  53.   ENV = false;
  54.   if(!quit)REC = true;
  55.  }
  56. }
  57. // FIN
  58. // FERMETURE DU SOCKET FILS
  59. if (shutdown(soc, SD_BOTH) == SOCKET_ERROR || closesocket(soc) == SOCKET_ERROR)
  60. {
  61.  cout << "La fermeture a echoue avec l'erreur : "<< WSAGetLastError() << endl;
  62.  return 103;
  63. }
  64. else
  65. {
  66.  cout << "Deconnexion du client." << endl;
  67. }
  68. // Libération du thread
  69. return 0;
  70. }


 
Le thread demarre après l'acceptation d'une connexion. Je vous fais grace de la fonction traitement, qui ne fait que manipuler des chaines et passer les booléens à true ou false (les enchainements d'envoi et de reception sont effectués correctement donc celle ci remplit son travail... De plus, lors des affichages cout << "Recu du client : " << recu << endl; et cout << "Envoye au client : " << envoi << endl; les chaines affichées sont correctes).

Reply

Sujets relatifs:

Leave a Replay

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