Forum Programmation.c Sockets...

Posté par  .
Étiquettes : aucune
0
28
déc.
2004
Bonjour à tous,

J'ai fait une fonction qui gère des entrées formattées sur un socket UDP à la scanf, qui ne marche plus :( En fait, il y a une fonction qui gère l'interpretation du formattage, et qui appelle au fur et a mesure la fonction buggée pour lire ce dont elle a besoin. Je me suis aperçu que ça ne marchait jusqu'il y a peu que parce que j'envoyais mes structures champ par champ et non pas entièrement linéarisées (vieux bug qui s'était fait discret, le bougre).
Depuis, je me bat avec recvfrom qui apparamment passe à la requête suivante dès que je l'appelle.

Exemple :
J'envoie une structure contenant un long (4 octets), un short, un long, et une chaine de 25 chars. Je swappe et je linéarise, et ça me fait 36 chars à envoyer d'un coup, alors qu'avec mon algo précédent j'aurais eu 4 requètes séparées.

Problème :
De l'autre coté, je récupère mon long en faisant un recvfrom (un vrai, avec flag 0) sur 4 octets, puis mon short avec 2 octets, et encore 4 octets pour le dernier long. Déjà, premier bug, à chaque fois je récupère les n premiers octets d'une nouvelle requête complète :(

Ensuite, pour la chaîne, c'est encore plus amusant car je ne connais pas la longueur à l'avance. Je lis donc avec le flag MSG_SEEK pour ne pas enlever les données du buffer jusqu'à ce que je rencontre un NULL ou que recvfrom plante. Mais comme je suis mal positionné, je ne récupère jamais ma chaîne... :'(

Solutions envisagées :

* Un buffer et un indice conservés par la fonction appelante et passés par adresse ? (pas de static, mon programme est theadé)
* Aller me coucher car il est bien tard (3:39 argh !)

Là je ne sais plus trop quoi faire, alors que me suggérez vous ?
  • # mauvaise methode

    Posté par  . Évalué à 3.

    > ça me fait 36 chars à envoyer d'un coup,
    et ensuite :
    > je ne connais pas la longueur à l'avance.

    ????

    si tu connais la longueur , met la en tete du message et boucle sur un select ou un poll jusqu'a avoir recu l'integralité de cette longueur (avec un timeout pour se proteger)
    • [^] # Re: mauvaise methode

      Posté par  . Évalué à 4.

      'excuse !
      j'ai lu trop vite. pas vu que c'etait de l'UDP.
      Ce que je conseillais c'est bon pour le TCP seulement.

      Pour l'UDP , comme l'indique justement SoWhat , il faut tout recuperer d'un coup sinon c'est perdu. Donc un gros buffer de 64k avec un seul recvfrom et ensuite on traite la reponse.
  • # Trop compliqué ton truc

    Posté par  . Évalué à 3.

    Pourquoi ne pas lire un gros buffer, d'un coup, qui aurait la taille
    max possible ?

    Après tu le parcours tout simplement...
    • [^] # Re: Trop compliqué ton truc

      Posté par  . Évalué à 3.

      En fait, je crois que c'est même la seule méthode valable quand on lit sur des sockets UDP. Un appel à 'recvfrom' lit autant de données que possible, dans la limite de l'espace mémoire fourni par l'utilisateur. Une fois l'appel à recvfrom terminé, le datagramme concerné est _perdu_. On n'est pas en TCP, mais bien en UDP. On doit lire datagramme par datagramme, contrairement à une socket TCP.
      L'avantage qu'on peut y voir, c'est que si l'emetteur fait un 'sendto' de 36 octets, on est _sûr_ que le datagramme reçu par l'autre bord aurra lui aussi une taille de 36 octets. Comme on ne connait aps forcément la taille avant le lecture, on utilise souvent un buffer de 65536 octets comme paramètre de l'appel à 'recvfrom', puis on recopie les données effectivement reçues dans un buffer de taille plus appropriée (si besoin).
      • [^] # Re: Trop compliqué ton truc

        Posté par  . Évalué à 1.

        En ethernet un paquet de 65535 octets c'est peu courant...

        Un buffer de 1500 suffit amplement pour un recvfrom ...
  • # Longueurs des données ...

    Posté par  . Évalué à 3.

    A première vue et sans rentrer dans les détails, je dirais que d'un point de vue purement protocolaire, tu devrais déjà appliquer strictement la même méthode d'un coté et de l'autre, c'est-à-dire récupérer la structure en entier, telle que tu l'as envoyée, puis lire ses champs. Donc, l'opération symétrique de celle de l'émission.

    Ensuite, il se peut que gcc (au fait, tu développes bien en C ?) fasse des optimisations, comme par exemple stocker un char ou un short sur un entier 32 bits pour faire des alignements en mémoire. Dans ce cas, tu risques d'envoyer du padding à travers le socket et de recevoir une structure imcomplète. Vérifie si c'est le cas à l'aide d'un sizeof(TaStructure), et en examinant les adresses de chacun de tes champs par rapport à celle de la structure elle-même.

    Bon courage.
  • # Merci beaucoup

    Posté par  . Évalué à 2.

    C'était bien les datagrammes qui étaient perdus :) J'ai réécris ma fonction en utilisant un buffer local lu au fur et a mesure et ça marche beaucoup mieux :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.