Les réponses à ces questions varient selon que vous utilisez un socket de flux ( SOCK_STREAM
) ou un socket de datagramme ( SOCK_DGRAM
) - dans TCP / IP, le premier correspond à TCP et le second à UDP.
Comment savez-vous quelle taille faire passer le tampon recv()
?
SOCK_STREAM
: Cela n'a pas vraiment trop d'importance. Si votre protocole est transactionnel / interactif, choisissez simplement une taille pouvant contenir le plus grand message / commande individuel auquel vous vous attendez raisonnablement (3000 est probablement très bien). Si votre protocole transfère des données en vrac, des tampons plus grands peuvent être plus efficaces - une bonne règle de base est à peu près la même que la taille du tampon de réception du noyau du socket (souvent quelque chose autour de 256 Ko).
SOCK_DGRAM
: Utilisez une mémoire tampon suffisamment grande pour contenir le plus gros paquet que votre protocole de niveau application envoie jamais. Si vous utilisez UDP, alors en général, votre protocole au niveau de l'application ne devrait pas envoyer de paquets de plus de 1400 octets, car ils devront certainement être fragmentés et réassemblés.
Que se passe-t-il si recv
obtient un paquet plus grand que le tampon?
SOCK_STREAM
: La question n'a pas vraiment de sens, car les sockets de flux n'ont pas de concept de paquets - ils ne sont qu'un flux continu d'octets. S'il y a plus d'octets disponibles à lire que votre mémoire tampon n'a de place, ils seront mis en file d'attente par le système d'exploitation et disponibles pour votre prochain appel recv
.
SOCK_DGRAM
: Les octets en excès sont ignorés.
Comment puis-je savoir si j'ai reçu l'intégralité du message?
SOCK_STREAM
: Vous devez créer un moyen de déterminer la fin du message dans votre protocole au niveau de l'application. Il s'agit généralement 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 peut être simplement une nouvelle ligne dans un protocole textuel, par exemple). Une troisième option, moins utilisée, consiste à imposer une taille fixe pour chaque message. Des combinaisons de ces options sont également possibles - par exemple, un en-tête de taille fixe qui comprend une valeur de longueur.
SOCK_DGRAM
: Un seul recv
appel renvoie toujours un seul datagramme.
Existe-t-il un moyen de faire en sorte qu'un tampon n'ait pas une quantité fixe d'espace, de sorte que je puisse continuer à y ajouter sans craindre de manquer d'espace?
Non. Cependant, vous pouvez essayer de redimensionner le tampon en utilisant realloc()
(s'il a été initialement alloué avec malloc()
ou calloc()
, c'est-à-dire).
recv
dans la mémoire tampon après le message partiel. Vous ne devriez pas utiliserstrstr()
sur le tampon brut rempli parrecv()
- il n'y a aucune garantie qu'il contienne un nul-terminator, donc il pourrait provoquer unstrstr()
crash.recv()
d'écrire plus d'octets qu'il ne reste d'espace.Pour les protocoles de streaming tels que TCP, vous pouvez à peu près définir votre tampon sur n'importe quelle taille. Cela dit, des valeurs communes qui sont des puissances de 2 telles que 4096 ou 8192 sont recommandées.
S'il y a plus de données que votre tampon, elles seront simplement enregistrées dans le noyau pour votre prochain appel
recv
.Oui, vous pouvez continuer à agrandir votre tampon. Vous pouvez faire un recv au milieu du tampon en commençant à offset
idx
, vous feriez:la source
Si vous avez une
SOCK_STREAM
socket,recv
récupère juste "jusqu'aux 3000 premiers octets" du flux. Il n'y a pas d'indications claires sur la taille du tampon: la seule fois où vous savez la taille d'un flux, c'est quand tout est fait ;-).Si vous avez une
SOCK_DGRAM
socket et que le datagramme est plus grand que le tampon,recv
remplit le tampon avec la première partie du datagramme, renvoie -1 et définit errno sur 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 non fiable (je sais qu'il existe des protocoles de datagramme fiables mais ils ne sont pas très populaires - je ne pourrais pas nommez-en un dans la famille TCP / IP, même si vous connaissez assez bien ce dernier ;-).Pour agrandir dynamiquement un tampon, allouez-le initialement avec
malloc
et utilisez-lerealloc
si nécessaire. Mais cela ne vous aidera pas àrecv
partir d'une source UDP, hélas.la source
Pour le
SOCK_STREAM
socket, la taille de la mémoire tampon n'a pas vraiment d'importance, car vous tirez simplement certains des octets en attente et vous pouvez en récupérer plus lors d'un prochain appel. Choisissez simplement la taille de tampon que vous pouvez vous permettre.Pour
SOCK_DGRAM
socket, vous obtiendrez la partie appropriée du message d'attente et le reste sera ignoré. Vous pouvez obtenir la taille du datagramme en attente avec l'ioctl suivant:Vous pouvez également utiliser les indicateurs
MSG_PEEK
etMSG_TRUNC
de l'recv()
appel pour obtenir la taille du datagramme en attente.Vous devez
MSG_PEEK
jeter un coup d'œil (et non recevoir) le message en attente - recv renvoie la taille réelle, non tronquée; et vous ne devezMSG_TRUNC
pas déborder de votre tampon actuel.Ensuite, vous pouvez juste
malloc(size)
le vrai tampon etrecv()
datagramme.la source
malloc()
pour un tampon de 64 Ko,MSG_TRUNC
est-ce inutile?SOCK_DGRAM
n'y a pas que UDP.Il n'y a pas de réponse absolue à votre question, car la technologie est toujours liée à la mise en œuvre. Je suppose que vous communiquez en UDP parce que la taille de la mémoire tampon entrante ne pose pas de problème à la communication TCP.
Selon RFC 768 , la taille de paquet (en-tête inclus) pour UDP peut aller de 8 à 65 515 octets. Ainsi, la taille à l'épreuve des pannes pour le tampon entrant est de 65 507 octets (~ 64 Ko)
Cependant, tous les gros paquets ne peuvent pas être correctement acheminés par les 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 maximal?
Quelle est la plus grande taille de paquet UDP sûre sur Internet
la source
16 ko est à peu près correct; si vous utilisez Gigabit Ethernet, chaque paquet peut avoir une taille de 9 Ko.
la source