Problème de sockets TCP - C - Programmation
Marsh Posté le 20-01-2006 à 10:25:25
Le fait d'avoir les messages dans les memes paquets c'est normal, ca fait partie du Nagle Algo (qui attend environ 200 ms avant d'envoyer ou cas ou d'autre donnees sont mise en queue pour le meme destinataire, cela evite les "petits paquets" et les collisions reseaux). Sur la meme machine en loopback, rien ne sort sur le reseau alors ca marche.
Tu peux "disabler" le Nagle, ou alors avant d'envoyer un autre message attendre un reponse du client.
Marsh Posté le 20-01-2006 à 10:55:07
J'ai ajouté ça dans mon code pour le désactiver sur la socket du serveur et sur chaque socket des clients :
Code :
|
avec disable_nagle = 1
Mais, ça ne fonctionne toujours pas....
Voici la fonction qui est lancée pour traiter les nouvelles connexions
Code :
|
Marsh Posté le 20-01-2006 à 11:25:43
Une autre solution, serait de d'envoyer la taille du message avant le message. Le client pourrait ainsi "couper" au bon endroit. Tu envois un int avec la length, dans le client tu lis d'abord sizeof(int), ensuite le nombre de caracteres. Attention si tu "mixes" les plateform a l'Endian case.
Marsh Posté le 20-01-2006 à 11:26:13
J'y avais pensé, mais techniquement, je ne peux pas mettre ta solution en oeuvre pour des raisons de compatibilité avec les clients....
En fait, ce qui se passe, c'est qu'il envoie un certain nombre de paquets correctement, puis ensuite, il les envoie n'importe comment alors que les données ont toutes la même taille
Marsh Posté le 20-01-2006 à 11:33:29
bin s'ils font tous la meme taille tu les découpent toi meme alors
il faut voir le tcp comme un flux, pas comme des paquets. c'est à toi de découper à l'arrivée.
Marsh Posté le 20-01-2006 à 11:42:40
Ce que je veux dire, c'est que là, j'envoie d'affilé plusieurs messages de même taille lors de l'initialisation de la connexion avec les clients, mais après, en fonctionnement normal, les messages sont de longueur variable.
Y a un truc auquel je pensais : vu que tous nos messages sont divisés en champs dont on connait le nombre, ça serait de rajouter un nouveau champ ne contenant que du bourrage. Dans ce cas, quelle est la taille maximale de la charge d'un paquet TCP sur un réseau ethernet ? Les clients pourront faire le tri sans problème , mais le découpage, c'est pas viable
Exemple de ce que j'envoie et reçois (c'est pour un jeu et entre les différents groupes, tout doit être compatible):
MAP_START |
Tout ce qui se trouve entre 2 "recu : " correspond à un paquet TCP...
Recu : MAP_START |
Marsh Posté le 20-01-2006 à 11:52:27
La taille des paquets n'est pas toujours la meme (MTU / MSS). De plus dans le cas de WAN etc il peut y avoir des "points" (routeurs ...) qui "redecoupent..donc pas viable.
Par contre comme je disais avant, en envoyant la longeur avant le message normalement t'as pas de probleme, tu peux meme ajouter un calcul de crc pour verifier si tu veux.
Ce genre de schema simplifie
cote serveur :
int SndMyMessage(socket s, const char* mess)
{
int i = strlen(mess);
snd(s, &i, sizeof(int));
snd(s, mess, i);
}
cote client :
int RcvMyMess(socket s)
{
int i;
char buff[256];
rcv(s, &i, sizeof(int));
rcv(s, buff, i);
}
Marsh Posté le 26-01-2006 à 19:09:00
Désolé de faire un UP, mais personne n'a d'idée pour mon problème ? Je ne peux vraiment pas toucher au code des clients pour des raisons d'interropérabilité...
Le programme marche impec sur le loopback ou si le réseau n'est pas saturé. Le problème, c'est que ce ne sont pas des situations réelles de fonctionnement...
Marsh Posté le 27-01-2006 à 13:49:19
A vrai dire, si tu ne peux modifier les clients, ça va être dure. Les clients sont donc mal programmé depuis le début.
De plus la solution d'envoyer un int avant n'est absolument pas portable. Car sur certain réseau, le bit de poid fort est mis avant et parfois après. Ce genre de converssion est vraiment lourde au niveau de la programmation.
C'est vrai que cette solution est à mon avis la meilleure. Mais faut pas passer par un entier, mais par une chaine de caractère de longueur fixe. Les chaines de caractère ne sont pas soumis à ce problème de bit de poids fort/faible.
Voila moi perso je ne vois pas de solution, pour moi c'est donc un problème au niveau de tes clients. C'est à eux à découper les données correctement.
Si comme tu dis, les longueurs sont variables, les clients doivent bien découper quelque part le paquet reçu. Il faut qu'il le sache. Donc à mon avis, le problème qui se pose ici (qui n'en est pas un à mon avis) tu ne saurais le régler sans aller modifier le client qui va avec...
Marsh Posté le 27-01-2006 à 14:51:26
Un int avant est une idee, pour la portabilite rien n'empeche d'envoyer sous format string de 4 bytes ("0124" ) et de faire un receive puis un atoi de cette chaine..
Mais bon si tu ne peux pas modifier les clients ... Peut etre mettre une tempo cote server, c'est a dire que tu attends par exemple 500 ms entre les messages pour le meme client. Dans ton server tu stockes l'heure d'evoie du dernier message et quand tu envois un nouveau tu verifies que l'ecart est bien "suffisant"..
Si les chaines que tu envois sont "null terminated", normalement le client detecte que le nombre de bytes recu est > strlen(chaine), donc il doit savoir qu'il y a une autre chaine... Si c'est des vrais "string" que tu envois, sois sur d'envoyer le '\0' final.
C'est un peu de bricolage, c'est vrai qu'un petit changement du soft client serait plus facile.
Marsh Posté le 27-01-2006 à 14:58:36
Desole, en regardant le code que tu as poste avant .. Apparemment tu recois un maximum de BUFFERSIZE dans le client. La solution c'est que le server envois toujours BUFFERSIZE en longeur (tu completes la fin avec des '\0').. Je ne vois que ca sans modifier le client.
Marsh Posté le 20-01-2006 à 09:42:14
Bonjour à tous !
J'ai écrit un petit serveur (sous Linux) permettant la réception et l'envoi de messages sur le réseau. Cependant, lors de l'envoi de plusieurs messages d'affilé à un même client, tous les messages sont placés dans le même paquet TCP au lieu d'être placé dans des paquets différents. Ce problème ne se produit pas si je fais tourner le client et le serveur sur la même machine via l'interface de loopback ou si je mets une temporisation d'une seconde entre chaque messages.
J'ai écrit une fonction send_to permettant d'envoyer un message à un client et qui est appelée par les couches supérieures de l'application et une fonction wait_client, lancée dans un thread, qui est chargée d'initialiser la connexion avec un nouveau client et de stocker les messages entrant dans une file de réception.
Je gère la liste des clients via une liste chainée (liste_client_t est une structure correspondant à un maillon de cette liste)
A tout hasard, voici le code de la fonction d'envoi des messages et celui des fonctions de réception
Voilà, je remercie d'avance ceux qui m'aideront à régler ce problème. Y a-t'il un appel système du même genre que fflush mais fonctionnant sur les sockets ?