transfert en UDP - C - Programmation
Marsh Posté le 16-04-2010 à 15:22:57
Mouais, j'ai aussi fait joujou avec ce genre de trucs, et avec UDP il n'y aura aucune garantie pour que ton paquet arrive en entier et dans l'ordre si jamais la taille dépasse le MTU du lien physique. Sur de l'ethernet à 100Mbit/s le MTU tourne autour de 1500 octets, sur du Gigabit c'est un peu plus.
Avec des paquets plus grand que ça, attends toi à une fragmentation et surtout une récupération dans le désordre quasi certaine.
Marsh Posté le 19-04-2010 à 09:27:53
Salut
Merci de ta réponse.
Est-ce que l'on peut dire à l'inverse que si on garantit qu'on aura un paquet à envoyer qui sera toujours inférieur à la taille de la MTU physique ne sera jamais fragmenté ?
Merci
Marsh Posté le 19-04-2010 à 10:37:33
Quand on utilise UDP, il ne faut pas penser que le "paquet" du recvfrom sera de la même longeur que le "paquet" du sendto. Par contre, il y a deux choses que je n'ai jamais vu avec mes programmes UDP :
- des inversion de "paquets" (mais peut-être que cela existe dans certains cas particuliers)
- des paquets de moins de 4 octets, sauf en fin de message.
En s'appuyant sur ces deux choses, on peut créer un système assez fiable qui consiste à envoyer en premier la longueur du message, puis le message ; et à la réception, à lire la longueur, puis à boucler jusqu'à l'arrivée du message en entier ; avec un timeout, et des réessais eventuels.
Marsh Posté le 19-04-2010 à 10:44:06
olivthill a écrit : Quand on utilise UDP, il ne faut pas penser que le "paquet" du recvfrom sera de la même longeur que le "paquet" du sendto. Par contre, il y a deux choses que je n'ai jamais vu avec mes programmes UDP : |
Salut
Merci de ta réponse, c'est exactement ce que je fais, mais j'ai l'impression que c'est insuffisant.
Je souhaite envoyer en broadcast UDP des données XML (assez courtes).
J'envoie donc des paquets de la forme suivante :
MAGIC NUMBER / LONGUEUR / CHECKSUM / DATA
MAGIC NUMBER est un entier sur 32 bits arbitraire
LONGUEUR est la longueur de mes datas
CHECKSUM est le checksum de mes datas (CRC32).
DATA correspond à mon buffer xml (ce n'est donc que du texte)
Mes 3 premiers entiers sont endianless , car il est possible que les 2 machines qui dialoguent soient différentes de ce coté.
Mon algo est assez simple :
je lis d'abord 12 octets. Si succès, je lis ensuite LONGUEUR data, et si succès, je teste le checksum. Si tout est ok, je retourne ma chaine à mon parser.
Mais j'ai l'impression que ce mécanisme est insuffisant, je me demande s'il ne faut pas que je gère également un numéro de séquenceur (départ, milieu, fin), et que j'envoie des paquets de taille fixe (sauf pour la fin, ou pour départ s'il est inférieur à la taille max du paquet).
Marsh Posté le 20-04-2010 à 09:40:30
Salut,
Bon, apparemment, je n'ai pas du bien comprendre comment fonctionne UDP, je rencontre quelques soucis pour transférer des datas via ce protocole.
Je souhaite envoyer des paquets XML en broadcast sur le réseau, et ceux-ci sont de taille variable (meme si j'arrive a garantir qu'ils sont plus petit qu'une trame).
Je procède donc de la façon suivante :
Code :
|
Mon emetteur envoie 160 octets : entete de 12 octets + 148 datas.
Si je fais comme ci dessus : select + lecture 12 octets + lecture du restant, le 2eme recvfrom me retourne une erreur : ressource temporary unavailable.
Si je mets un select entre les 2, le 2eme select ne voit pas de data , je ne peux donc pas lire les 148 restants.
Pire que ca, ma fonction étant rappelée plus tard, elle relit 12 octets, et trouve bien l'entete de ma trame suivante. Cela signifie que mes 148 octets sont tout simplement perdus.
Si par contre je lis 160 octets d'un coup (select + recvfrom de 160 octets), pas de pb, je récupère la totalité.
Cela signifierait donc que UDP ne permet pas de lire une trame (un DATAGRAM) en plusieurs fois ? Dans ce cas, très difficile d'utiliser UDP avec des paquets de taille variable , et je comprends pourquoi dans la doc il est écrit qu'UDP est plus adapté à un protocole avec des paquets de taille fixe.
Quelqu'un peut me confirmer ? Ou m'éclairer sur des points que je n'aurais pas compris ?
merci
Marsh Posté le 20-04-2010 à 11:12:39
Mon programme gère la reception de fichiers PDF.
Le flux contient un entête "File:%d:%s", puis les octets du fichier PDF.
Voici mon programme pour infos.
Code :
|
Marsh Posté le 20-05-2011 à 15:27:22
J'ai trouvé la réponse à une de mes questions :
Citation : |
-> http://tangentsoft.net/wskfaq/general.html
Citation : |
Conclusion : un datagramme UDP est fragmenté ( en fragment de taille max = MTU ) puis ré assemblé dans l'ordre, si tous les fragments sont bien reçus.
Marsh Posté le 20-05-2011 à 15:45:38
Par expérience: on ne peut pas faire de lecture fragmentée d'un datagramme. Donc la solution de lire d'abord l'entête, puis le reste du message n'est possible qu'à une condition : utiliser l'option MSG_PEEK, qui ne retire pas les données du tampon de réception après lecture.
Je me pose des questions sur la performance du truc, parce que ça oblige à faire au moins deux lectures (une avec MSG_PEEK pour connaitre la taille du message à lire, et une autre pour sortir l'intégralité du message).
Il y a aussi l'option, avant la lecture, d'appeler ioctl avec l'option FIONREAD. Cela te retourne la taille du prochain datagramme dans le tampon.
Marsh Posté le 20-05-2011 à 16:22:18
shaoyin a écrit : Par expérience: on ne peut pas faire de lecture fragmentée d'un datagramme. Donc la solution de lire d'abord l'entête, puis le reste du message n'est possible qu'à une condition : utiliser l'option MSG_PEEK, qui ne retire pas les données du tampon de réception après lecture. |
Je te remercie de cette info, cela répond à ma 2ème interrogation. Comme tu as pu le remarquer, mon message initial date de plus d'un an , donc j'ai trouvé une solution intermédiaire, je postais juste une des réponses que j'avais trouvé au cas où cela pouvait interesser quelqu'un.
Ma solution est : j'ai une taille variable mais elle est bornée. L'algo est donc :
Code :
|
cela fonctionne très bien et sans problème
Marsh Posté le 16-04-2010 à 15:10:10
Salut
Ce n'est pas vraiment une question C à proprement parler, mais je pense que c'est quand même la meilleure catégorie pour en parler. Si jamais la catégorie n'est pas bonne, pouvez vous m'indiquer la plus appropriée ?
Voici mon problème :
J'ai un système multi-client / multi-serveur qui tourne depuis un moment et sur lequel je veux apporter une modification notamment au niveau des transferts UDP.
Chaque serveur envoie sur l'adresse broadcast du réseau un ordre UDP (sur port N) toutes les secondes afin d'indiquer leur présence, ainsi que certains de leurs paramètres (qui peuvent varier. Ex : point de montage, taille restante ou signature MD5 de données sur celui-ci).
Chaque client envoie également sur l'adresse broadcast un ordre UDP (sur port N+1) indiquant également leur présence aux serveurs. Ceci toutes les secondes également.
Ainsi, chaque serveur ecoute sur N+1, et chaque client sur N, et ils travaillent en fonction de ce qu'ils recoivent.
les données envoyées par le client et par le serveur n'excéderont jamais 1000 octets.
Maintenant, étant en train d'écrire les algos pour recevoir les données, je suis pris d'un affreux doute :
- Je sais qu'UDP ne garantit par l'ordre des paquets, mais aucun problème car les données sont intègres en un seul paquet, et il n'y a pas de notion temporelle dans ce que je recois. Ainsi, je peux recevoir les paquets de chaque serveur dans le désordre, ce qui ne me dérangerait pas (si c'est ponctuel).
- Par contre, je n'ai pas pensé à la fragmentation. En effet, le réseau peut me fragmenter une trame UDP, mais est-ce que le réseau me garantit que le réassemblage sera fait avant que je recoive mon paquet ? En d'autres terme, si j'envoie un paquet dont je garantis la taille inférieure à la taille max d'un paquet, il arrivera dans le bon ordre ?
Par exemple : j'envoie 800 octets avec S1 , et 900 octets avec S2. Est ce que je suis garanti de recevoir S1 puis S2 entier, ou S2 puis S1 entier ou puis je recevoir un truc incohérent du style : 400/900 S2 , 800 S1 , 500/900 S2 (si par exemple sur le réseau, j'ai un équipement qui me fragmente les trames de S2 ) ?
- Maintenant, si j'étends la longueur de mes données à envoyer au delà de 1000 octets, ou plus simplement au delà de la taille d'un paquet UDP, je suppose que mes datas seront fragmentés en plusieurs paquets, mais seront ils réassemblés dans l'ordre à la réception ou pas du tout ?
Par exemple: Depuis mon serveur , je fais un SendTo(data) , avec data = 65536 octets , est ce que le RecvFrom(data) du client va me récupérer data dans l'ordre, ou dans le désordre, ou pire ! mélangé avec les datas d'un autre serveur (car on travaille sur une adresse de broadcast).
Si c'est le cas, est ce que quelqu'un peut me confirmer que UDP n'est pas adapté pour envoyer des paquets trop gros sans mécanisme de réassemblage.
Merci pour vos réponses