Quelle doit être la taille de mon tampon recv lorsque j'appelle recv dans la bibliothèque socket?

j'ai quelques questions sur la bibliothèque socket en C. Voici un extrait de code auquel je vais faire référence dans mes questions.

char recv_buffer[3000];
recv(socket, recv_buffer, 3000, 0);
  1. comment décider de quelle taille faire recv_buffer? J'utilise 3000, mais c'est arbitraire.
  2. que se passe-t-il si recv() reçoit un paquet plus grand que mon tampon?
  3. Comment puis-je savoir si j'ai reçu le message entier sans appeler recv à nouveau et le faire attendre à jamais quand il n'y a rien à être reçu?
  4. y a-t-il un moyen de faire qu'un tampon n'ait pas une quantité fixe d'espace, de sorte que je puisse y ajouter sans crainte de manquer d'espace? peut-être utiliser strcat pour concaténer la dernière réponse recv() au tampon?

je sais que c'est beaucoup de questions en une seule, mais j'apprécierais toute les réponses.

112
demandé sur Chen XinZhen 2010-05-19 04:19:47

6 réponses

les réponses à ces questions varient selon que vous utilisez une socket stream ( SOCK_STREAM ) ou une socket datagram ( SOCK_DGRAM ) - dans TCP/IP, la première correspond à TCP et la seconde à UDP.

Comment savez-vous quelle taille faire passer le tampon à recv() ?

  • SOCK_STREAM : ça n'a pas vraiment d'importance. Si votre protocole transactionnel / interactive one il suffit de choisir une taille qui peut contenir le plus grand message / commande individuelle à laquelle vous pouvez raisonnablement vous attendre (3000 est probablement très bien). Si votre protocole est en train de transférer des données en vrac, alors des tampons plus gros peuvent être plus efficaces - une bonne règle empirique est à peu près la même que la taille du tampon de réception du noyau (souvent quelque chose autour de 256kB).

  • SOCK_DGRAM : utilisez un tampon assez grand pour contenir le plus gros paquet que votre le protocole au niveau de l'application envoie toujours. Si vous utilisez UDP, alors en général votre protocole au niveau de l'application ne devrait pas envoyer de paquets plus grands que 1400 octets, car ils auront certainement besoin d'être fragmentés et réassemblés.

que se passe-t-il si recv obtient un paquet plus grand que le buffer?

  • SOCK_STREAM : la question n'a pas vraiment de sens puisque parce que sockets flux n'ont pas un concept de paquets - ils sont juste un flux continu d'octets. S'il y a plus d'octets disponibles à lire que votre tampon n'a de place, ils seront placés en file d'attente par le système D'exploitation et disponibles pour votre prochain appel à recv .

  • SOCK_DGRAM : les octets excédentaires sont éliminés.

Comment puis-je savoir si j'ai reçu le message en entier?

  • SOCK_STREAM : vous devez construire un moyen de déterminer la fin du message dans votre protocole au niveau de l'application. En général, il s'agit d'un préfixe de longueur (commençant chaque message par la longueur du message) ou d'un délimiteur de fin de message (qui pourrait simplement être une nouvelle ligne dans un protocole basé sur du texte, par exemple). Une troisième option, moins utilisée, consiste à prescrire une taille fixe pour chaque message. Les combinaisons de ces options sont également possible-par exemple, un en-tête de taille fixe qui inclut une valeur de longueur.

  • SOCK_DGRAM : un seul appel recv renvoie toujours un seul datagramme.

" y a-t-il un moyen pour moi de faire qu'un tampon n'ait pas une quantité fixe d'espace, de sorte que je puisse continuer à y ajouter sans crainte de manquer d'espace?

Pas de. Cependant, vous pouvez essayer de redimensionner le tampon en utilisant realloc() (s'il a été initialement attribué avec malloc() ou calloc() , c'est-à-dire).

200
répondu caf 2016-10-29 02:23:09

pour les protocoles de streaming tels que TCP, vous pouvez régler votre tampon à n'importe quelle taille. Cela dit, les valeurs communes qui sont des pouvoirs de 2 comme 4096 ou 8192 sont recommandées.

S'il y a plus de données que votre tampon, il sera simplement sauvegardé dans le noyau pour votre prochain appel à recv .

Oui, vous pouvez continuer à faire pousser votre tampon. Vous pouvez faire un recv dans le milieu du tampon à partir de l'offset idx , vous feriez:

recv(socket, recv_buffer + idx, recv_buffer_size - idx, 0);
15
répondu R Samuel Klatchko 2010-05-19 00:51:45

Si vous avez un SOCK_STREAM socket recv juste "jusqu'à la première 3000 octets" à partir du flux. Il n'y a pas de directives claires sur la taille de la zone tampon: la seule fois où vous savez quelle est la taille d'un cours d'eau, c'est quand tout est terminé;-).

si vous avez une socket SOCK_DGRAM , et que le datagramme est plus grand que le buffer, recv remplit le buffer avec la première partie du datagramme, retourne -1, et définit errno à EMSGSIZE. Malheureusement, si le protocole est UDP, cela signifie que le reste du datagramme est perdu -- une partie de la raison pour laquelle UDP est appelé un protocole peu fiable (je sais qu'il y a des protocoles de datagramme fiables mais ils ne sont pas très populaires -- Je ne pouvais pas en nommer un dans la famille TCP/IP, malgré le fait de connaître ce dernier assez bien;-).

pour faire pousser un tampon dynamiquement, attribuez-le d'abord avec malloc et utilisez realloc si nécessaire. Mais cela ne vous aidera pas avec recv d'une source UDP, hélas.

13
répondu Alex Martelli 2010-05-19 00:28:05

pour SOCK_STREAM socket, la taille du tampon n'a pas vraiment d'importance, parce que vous tirez juste quelques octets d'attente et vous pouvez en récupérer plus dans un appel suivant. Choisissez la taille de tampon que vous pouvez vous permettre.

pour SOCK_DGRAM socket, vous obtiendrez la partie d'ajustement du message d'attente et le reste sera jeté. Vous pouvez obtenir la taille du datagramme en attente avec l'ioctl suivant:

#include <sys/ioctl.h>
int size;
ioctl(sockfd, FIONREAD, &size);

vous pouvez également utiliser MSG_PEEK et MSG_TRUNC drapeaux de l'appel recv() pour obtenir la taille du datagramme en attente.

ssize_t size = recv(sockfd, buf, len, MSG_PEEK | MSG_TRUNC);

alors vous pouvez juste malloc() le tampon et récupérer le datagramme.

2
répondu smoku 2016-08-09 18:49:19

il n'y a pas de réponse absolue à votre question parce que la technologie est toujours liée à la mise en œuvre-spécifique. Je suppose que vous communiquez en UDP parce que la taille du tampon entrant n'apporte aucun problème à la communication TCP.

selon RFC 768 , la taille du paquet (en-tête incluse) pour UDP peut varier de 8 à 65 515 octets. Ainsi, la taille de preuve d'Échec pour le tampon entrant sera 65 507octets (~64KB)

cependant, tous les gros paquets ne peuvent pas être correctement routés par des périphériques réseau, reportez-vous à la discussion existante pour plus d'informations:

Quelle est la taille optimale d'un paquet UDP pour un débit maximum?

Quelle est la plus grande taille de paquet UDP sûre sur L'Internet

1
répondu YeenFei 2017-05-23 10:31:37

16Ko est à peu près à droite; si vous utilisez gigabit ethernet, chaque paquet pourrait avoir une taille de 9ko.

-4
répondu Andrew McGregor 2010-05-19 00:46:48