J'ai un bogue rare qui semble se produire lire une prise.
Il semble que, lors de la lecture des données, je n'obtiens parfois que 1 à 3 octets d'un package de données plus grand que cela. P> Comme j'ai appris de la programmation des tuyaux, je reçois toujours au moins 512 octets tant que l'expéditeur fournit suffisamment de données. P>
aussi mon expéditeur transmet au moins> = 4 octets à tout moment - Je pensais donc que au moins 4 octets seront reçus à la fois au début (!!) de la transmission. P>
dans 99,9% de tous les cas, mon hypothèse semble contenir ... mais Il y a vraiment de rares cas, lorsque moins de 4 octets sont reçus. Il me semble ridicule, pourquoi le système de réseautage devrait faire cela? P>
Est-ce que quelqu'un en sache plus? P>
Voici le code de lecture que j'utilise: p>
mySock, addr = masterSock.accept() mySock.settimeout(10.0) result = mySock.recv(BUFSIZE) # 4 bytes are needed here ... ... # read remainder of datagram ...
8 Réponses :
Autant que je sache, ce comportement est parfaitement raisonnable. Les sockets peuvent, et probablement seront forts> fragmenter vos données lorsqu'ils le transmettent. Vous devez être prêt à gérer de tels cas en appliquant des techniques de mise en mémoire tampon appropriées. P>
En revanche, si vous transmettez les données sur le localhost et que vous obtenez seulement 4 octets, cela signifie probablement que vous avez un bug ailleurs dans votre code. P>
Edit: une idée - Essayez de reposer un sniffer de paquet et voyez chaque fois que le paquet transmis sera plein ou non; Cela pourrait vous donner une idée de votre bogue dans votre client ou sur votre serveur. em> p>
En actes, mon code se déroule en fait sur localhost - quelque chose qui rend la chose encore plus étrange!
Merci pour l'idée du paquet-Sniffer. Mais je crains que cela ne m'aide pas beaucoup, puisque les ennuis ne se produisent que dans de rares cas et je ne le vois qu'après que c'est arrivé ... Le package Sniffer est le plus susceptible de retarder ...
Si les données sont fragmentées ou non dépendent vraiment de l'allocation des choses. TCP tente de tamponner un segment complet / MTU avant qu'elle envoie afin de pouvoir utiliser efficacement la bande passante. Le MTU le plus courant que vous rencontrez est d'environ 1500 octets pour Ethernet. Si vous transmettez moins que cela, il est peu probable que la fragmentation soit votre problème. Votre bug est probablement ailleurs.
Il suffit de courir le sniffer de paquet tout le temps. Stockez les octets sur le disque et examinez-les plus tard.
TCP fournit un flux d'octets, ce n'est pas axé sur le message et ne fournit pas de frontières. Vous devez traiter est en tant que tel. Une écriture des appels pourrait prendre plusieurs appels de lecture pour obtenir ces données. Les données de plusieurs appels écrits pourraient être lues par un appel de lecture. Et quoi que ce soit entre cela.
@nos: Merci pour la réponse qui est la première définitive. C'est ce que j'attendais - quelqu'un qui peut expliquer un peu plus sur les arrière-plans. J'exclureais maintenant un problème sur le côté de l'expéditeur, mais laissez tomber mon hypothèse.
de la page Homme Linux de RECV http://linux.about.com/ Bibliothèque / CMD / BLCMDL2_RECV.HTM : P>
Les appels de réception renvoient normalement tout Données disponibles, jusqu'à la demande montant plutôt que d'attendre Réception du montant total demandé. p> blockQuote>
Donc, si votre expéditeur émet toujours des octets, l'appel ne donnera que ce qui a été transmis jusqu'à présent. P>
Mais il est simplement déraisonnable de transmettre 1 à 3 octets, lorsque l'expéditeur transmis peut-être 10 octets dans un simple appel à un simple i>. Pourquoi une bibliothèque devrait-elle faire cela ??
C'est un syscall qui doit considérer chaque cas qui peut arriver. Vous le faites de mal lorsque vous vous en appelez pour obtenir toutes les données que vous envoyez dans un appel. Que devrait-on recouvert () lorsque vous envoyez 1000 octets et que le tampon n'a que 500 octets? Que faire lorsque la chose est retransmise en raison d'erreurs, fragmentées, etc. Il est courant de lire dans un tampon jusqu'à ce que vous envoyiez une chaîne de terminaison (\ 0 est courante), afin que vous sachiez qu'un message a été reçu.
Je ne dis pas, que tu n'aurais peut-être pas raison. Ce que je dis, c'est que pas d'explication raisonnable n'est disponible pour moi. Vos nouveaux exemples dans le commentaire mènent dans la mauvaise direction, car il s'agit des 4 premiers octets d'un nouveau bloc de transmission.
Encore une fois: "Les appels de réception renvoient normalement toutes les données disponibles [...]". Vous le faites mal et vous assumez des choses d'une fonction que les fonctions clairement i> ne le fournissent pas. Il dit explicitement dans le manchon. Vous pourriez aussi bien remettre en question pourquoi votre voiture ne volera pas. Maintenant, je pourrais répondre à cette question techniquement, mais je ne suis pas de noyau dev, donc je ne pouvais donc pas vous dire quelle est la raison technique de votre question. Néanmoins, vous attendez un comportement de RECV (), que le manuel exclut explicitement.
Si l'expéditeur envoie 515 octets et que votre BUFSIZE est 512, le premier RECV reviendra 512 octets et le prochain retournera 3 octets ... pourrait-il être ce qui se passe? P>
(Ce n'est qu'un seul cas parmi beaucoup qui entraînera un RECV de 3 octets d'un envoi plus vaste ...) P>
Je voulais préciser, que mon problème se passe bien au début d'une connexion fraîchement établie.
+1 Pour compenser le vote non envisagé, injustifié, car la réponse est partielle mais correcte.
@ALEX: Encore une fois, j'ai expliqué mon problème vraiment très détaillé et les affiches qui l'ont juste ignorée. Êtes-vous la feteal étant le sherif ici? J'ai fait clairement mes déclarations et quand je bowevote, alors ce n'est pas parce que la réponse est partielle, mais parce que c'est (absolument) pas utile et / ou ignorant la question. Je pourrais aussi donner une conférence sur la musique ici.
Je suis surpris que quiconque vous aide du tout avec votre attitude.
Je suis surpris de l'attitude dans ce forum ici. Quand quelqu'un dit qu'une réponse n'était pas utile (c'est ainsi que cela se lit dans mon navigateur lorsque je survole sur le bouton Downvote), tout le monde est blessé et le n'aime pas - parce qu'il semble ne pas être assez "poli". Aussi, j'ai eu au moins deux ou trois bowvotes pour ma question depuis - une fois que j'imagine d'Alex (depuis le match de temps - avant de lui répondre). Et je devrais être silencieux ?? Je suis surpris que je suis toujours dans ce forum curieux ici.
@Juergen: Ne vous inquiétez pas, il équilibre à long terme. Je ne pensais pas que votre question était inappropriée et j'avais vu le bowvote mais que je ne l'ai pas contesté, car vous avez souligné correctement que je n'avais pas répondu à votre question. J'avais pris votre commentaire à bord et je cherchais quelque chose qui pourrait être utile de réviser ma réponse. Il y a quelques personnes autour de qui n'aiment pas voir "réponses utiles qui ne s'appliquent pas dans la présente affaire" ont voté, car elle pourrait décourager de nouvelles personnes d'essayer de contribuer davantage si elles sont votées tôt. Tout le monde ne partage pas cette vue, alors ne vous découragez pas.
Pour le compte rendu, le consensus autour d'ici semble être de laisser un commentaire expliquant pourquoi la réponse n'était pas utile et de descendre la réponse vers 0, mais pas plus bas ... Les scores négatifs semblent principalement être donnés pour des informations incorrectes contenant des informations incorrectes qui contiennent des informations incorrectes , sont antagonistes ou argumentatifs, ou semblent être spams et inutiles. (L'idée étant de donner l'impression de «merci d'avoir essayé d'être utile, même si cela ne fonctionnait pas cette fois», vs «Vous ne jouez pas bien, partez».).
@Stopor: Merci pour votre réponse. Cela pourrait être que j'ai bu en dessous de 0 - j'approst-je pour cela - parce que je ne connaissais pas le consensus. Je jouais "par la lettre" et qui a lu dans mon cas "La réponse n'est pas utile" Qu'est-ce que c'était pour moi.
@ Juergen: Bien sûr, je comprends et je n'ai pris aucune infraction. Il n'y a pas de règles difficiles et rapides ici, tout le monde fait juste ce qu'ils pensent est la meilleure chose à ce moment-là. Je ne vote pas nécessairement selon ces lignes directrices, soit - ce n'est que le motif que j'ai remarqué.
Je suppose que vous utilisez TCP. TCP est un protocole basé sur le flux sans aucune idée de paquets ni de frontières de message.
Cela signifie que lorsque vous faites une lecture, vous pouvez obtenir moins d'octets que votre demande. Si vos données sont 128k, par exemple, vous ne pouvez obtenir que 24K sur votre première lecture vous oblige à lire à nouveau pour obtenir le reste des données. P>
pour un exemple en C: P>
int read_data(int sock, int size, unsigned char *buf) { int bytes_read = 0, len = 0; while (bytes_read < size && ((len = recv(sock, buf + bytes_read,size-bytes_read, 0)) > 0)) { bytes_read += len; } if (len == 0 || len < 0) doerror(); return bytes_read; }
Parce que ça me couture, que vous avez seulement lu le titre. J'ai décrit un cas très spécial et vous avez donné une réponse générique. Pour le mettre en moins de mots: ce n'était pas utile pour moi!
1 Pour compenser le bowvote inexpliqué et injustifié, car la réponse est correcte (peut ou non rendre l'op heureux, mais il n'y a rien de mal à cela en soi).
@Alex: Comment vous sentiriez-vous, quand vous m'avez demandé au cancer du poumon et je vous ai donné une conférence sur les vitamines?
Comme d'autres l'ont noté, si vous n'appelez pas Recv dans une boucle, votre code est faux. Écrire un code de réseau correct sur le côté RECV i> sera utile dans la mesure où cela vous aide à réduire / isoler l'endroit où le problème pourrait être.
+1 aussi. Comment vous sentiriez-vous si vous avez donné une bonne solution et que vous êtes ignoré parce que celui qui a posé la question n'a pas le problème? La boucle tandis que la boucle est un exemple parfaitement droit pour recevoir des octets sur le réseau. Vous ne voulez tout simplement pas repenser votre propre solution.
Je vais toujours essayer de vous aider en l'expliquant un peu plus. Vous avez une situation dans laquelle vous revendiquez les envois latéraux de l'envoi> = 4 octets, mais vous seul NECV <4 octets. Pour le moment, vous ne savez pas si le problème est sur le côté RECV, le côté envoi ou quelque part entre les deux. En appelant RECV dans une boucle, vous pouvez déterminer définitivement si le problème est sur le côté de la largeur de rapport. Par exemple, si vous appelez RECV dans une boucle, obtenez 3 octets, puis la prochaine itératation de la boucle se bloque, vous pouvez déterminer que le 4ème octet n'est pas en train d'être reconnu probable i> parce qu'il y a un bug sur le côté envoi.
@ Juergen Les spécificités ne sont pas aussi intéressantes, car il n'ya aucun moyen de contrôler la manière dont le système d'exploitation gère vos données de manière significative. Et il y a beaucoup, trop de variables externes inculpent comment le système d'exploitation gère ces données. Vous devez suivre les règles générales pour faire fonctionner le code de réseau. C'est loin, beaucoup plus impliqué que le code d'exemple typique de TCP que vous trouvez par Googling.
@nos: Comme je l'ai dit avant - la meilleure réponse encore.
Qu'y a-t-il avec le dernier vote? Si quelqu'un va bowervote une telle réponse ancienne et prospère, laissez au moins un commentaire pourquoi.
C'est juste la façon dont TCP fonctionne. Vous n'allez pas avoir toutes vos données à la fois. Il y a juste trop de problèmes de chronométrage entre l'expéditeur et le récepteur, notamment le système d'exploitation des expéditeurs, les moteurs, les routeurs, les commutateurs, les fils eux-mêmes, les récepteurs Nic, le système d'exploitation, etc. Il existe des tampons dans le matériel et dans le système d'exploitation. P. >
Vous ne pouvez pas supposer que le réseau TCP est identique à un tuyau d'exploitation. Avec le tuyau, c'est tout le logiciel, il n'y a donc aucun coût dans la livraison de l'ensemble du message à la fois pour la plupart des messages. Avec le réseau, vous devez supposer qu'il y aura des problèmes de chronométrage, même dans un réseau simple. P>
C'est pourquoi RECV () ne peut pas vous donner toutes les données à la fois, il peut tout simplement pas être disponible, même si tout fonctionne correctement. Normalement, vous appellerez RECV () et attrapez la sortie. Cela devrait vous dire combien d'octets que vous avez reçus. Si cela est moins que prévu, vous devez continuer à appeler Recv () (comme cela a été suggéré) jusqu'à ce que vous obteniez le nombre correct d'octets. Sachez que dans la plupart des cas, RECV () renvoie -1 sur une erreur, vérifiez-vous et vérifiez votre documentation pour les valeurs errno. Eagain en particulier semble causer des problèmes de personnes. Vous pouvez en lire sur Internet pour plus de détails, mais si je me souviens, cela signifie qu'aucune donnée n'est disponible pour le moment et vous devriez essayer à nouveau. P>
En outre, il ressemble à votre message que vous êtes sûr que l'expéditeur envoie les données dont vous avez besoin envoyées, mais juste pour être terminée, vérifiez ceci: http://beej.us/guide/bgnet/output/ html / multipage / avancé.html # sendall p>
Vous devriez faire quelque chose de similaire sur la touche RECV () pour gérer les reçus partiels. Si vous avez une taille de paquet fixe, vous devez lire jusqu'à ce que vous obteniez la quantité de données que vous attendez. Si vous avez une taille de paquet variable, vous devez lire jusqu'à ce que vous ayez l'en-tête qui vous indique la quantité de données que vous envoyez (), puis lisez que beaucoup plus de données. P>
La réponse simple à votre question "Lisez à partir de la prise: est-elle garantie au moins obtenir x octets?", est <, est à partir de celui-ci, il est clair que Vous mentionnez Si le problème est reproductible, vous pouvez désactiver le délai d'attente (qui ne semble pas être manipulant) et voir si cela corrige le problème . p> p> recv () code> n'est pas nécessaire pour revenir autant d'octets que vous avez demandé. En outre, parce que vous appelez
settimeout (10.0) code>, il est possible que certains, mais pas tous, des données sont reçues à proximité du délai d'expiration pour le
recv () code>. Dans ce cas
RECV () code> retournera ce qu'il a lu - qui sera inférieur à celui que vous aurez demandé (mais la composition <4 octets semble-t-il peu probable). P>
Datagramme CODE> Dans votre question qui implique que vous utilisez (sans connexion) des sockets UDP (non de TCP). La distinction est décrit ici . Le code affiché ne montre pas la création de socket afin que nous puissions deviner ici, cependant, ce détail peut être important. Il peut vous aider si vous pouviez poster un échantillon plus complet de votre code. P>
Le délai d'attente n'est pas le problème ici - j'ai aussi vérifié que. En cas de délai d'attente, une exception serait incendiée - et donc une réaction différente se produirait dans mon programme. J'ai maintenant changé mon programme, tel qu'une boucle est impliquée également au début. Mais je suis toujours curieux, lequel des réponses était la plus utile. Le vôtre et les commentaires des Nos me semblent mieux pour moi.
@Juergen: une exception temporelle ne sera soulevée que si nul b> n'a été reçu. La condition que je décris est lorsque certaines données, moins que celle demandées par RECV () code>, sont reçues juste avant le délai d'attente.
RECV () CODE> reviendra lorsque le délai d'attente expire et renvoie moins de données que celle demandée. Comme je l'ai dit, il est très peu probable que cela soit systématiquement <4 octets, mais je suppose que c'est possible. La lecture d'une boucle est la bonne façon de gérer votre problème.
Si vous êtes toujours intéressé, des modèles tels que ceci: peut créer la fenêtre idiote de la fenêtre. p> cocher Ceci Out P> P>
Utiliser Robert S. Barnes écrit l'exemple en c. P> Mais vous pouvez utiliser Python 2.x avec des bibliothèques Python standard: p> avis, que recv_into (...) code> méthode à partir du module code> code>.
sz code> renvoyé par
réadientablement () Code> La fonction peut être supérieure à
n code>. p> p>
Puis-je demander combien d'octets que vous envoyez et ce que les bufizes sont définis pour s'il vous plaît? Les autres réponses expliquent qu'il s'agit de comportement parfaitement normal et que vous devriez toujours faire la lecture / RECV dans une boucle jusqu'à ce qu'elle se lit suffisamment, mais il pourrait être possible de déterminer pourquoi vous obtenez cela dans ce cas
Vérifiez-vous réellement la valeur de retour de l'envoi pour vérifier combien d'octets sont envoyés?
Bonjour Robert, cette suggestion est bonne. Maintenant oui. Pourrait aussi créer des problèmes ...
Avez-vous déjà découvert ce que le problème était avec votre programme?