Die Antworten auf diese Fragen variieren je nachdem, ob Sie einen Stream-Socket ( SOCK_STREAM
) oder einen Datagramm-Socket ( SOCK_DGRAM
) verwenden. Innerhalb von TCP / IP entspricht ersteres TCP und letzteres UDP.
Woher wissen Sie, wie groß der Puffer sein soll recv()
?
SOCK_STREAM
: Es ist nicht wirklich wichtig. Wenn es sich bei Ihrem Protokoll um ein transaktionales / interaktives Protokoll handelt, wählen Sie einfach eine Größe aus, die die größte einzelne Nachricht / den größten Befehl enthalten kann, die Sie vernünftigerweise erwarten würden (3000 ist wahrscheinlich in Ordnung). Wenn Ihr Protokoll Massendaten überträgt, können größere Puffer effizienter sein - eine gute Faustregel entspricht in etwa der Größe des Kernel-Empfangspuffers des Sockets (häufig etwa 256 KB).
SOCK_DGRAM
: Verwenden Sie einen Puffer, der groß genug ist, um das größte Paket aufzunehmen, das Ihr Protokoll auf Anwendungsebene jemals gesendet hat. Wenn Sie UDP verwenden, sollte Ihr Protokoll auf Anwendungsebene im Allgemeinen keine Pakete senden, die größer als etwa 1400 Byte sind, da diese sicherlich fragmentiert und neu zusammengesetzt werden müssen.
Was passiert, wenn recv
ein Paket größer als der Puffer wird?
SOCK_STREAM
: Die Frage ist nicht wirklich sinnvoll, da Stream-Sockets kein Paketkonzept haben - sie sind nur ein kontinuierlicher Stream von Bytes. Wenn mehr Bytes zum Lesen verfügbar sind, als Ihr Puffer Platz bietet, werden sie vom Betriebssystem in die Warteschlange gestellt und stehen für Ihren nächsten Aufruf an zur Verfügung recv
.
SOCK_DGRAM
: Die überschüssigen Bytes werden verworfen.
Wie kann ich feststellen, ob ich die gesamte Nachricht erhalten habe?
SOCK_STREAM
: Sie müssen eine Möglichkeit zum Bestimmen des Nachrichtenende in Ihr Protokoll auf Anwendungsebene integrieren. Im Allgemeinen ist dies entweder ein Längenpräfix (wobei jede Nachricht mit der Länge der Nachricht beginnt) oder ein Trennzeichen für das Ende der Nachricht (das beispielsweise nur eine neue Zeile in einem textbasierten Protokoll sein kann). Eine dritte, weniger genutzte Option besteht darin, für jede Nachricht eine feste Größe festzulegen. Kombinationen dieser Optionen sind ebenfalls möglich - beispielsweise ein Header mit fester Größe, der einen Längenwert enthält.
SOCK_DGRAM
: Ein einzelner recv
Aufruf gibt immer ein einzelnes Datagramm zurück.
Gibt es eine Möglichkeit, einen Puffer ohne festen Speicherplatz zu erstellen, damit ich ihn weiter erweitern kann, ohne befürchten zu müssen, dass ihm der Speicherplatz ausgeht?
Nein. Sie können jedoch versuchen, die Größe des Puffers mithilfe von zu ändern realloc()
(wenn er ursprünglich mit malloc()
oder zugewiesen calloc()
wurde).
recv
in den Puffer nach der Teilnachricht einfügen. Sie solltenstrstr()
den mit gefüllten Rohpuffer nicht verwendenrecv()
- es gibt keine Garantie dafür, dass er einen Nullterminator enthält, sodass erstrstr()
zum Absturz führen kann.recv()
mehr Bytes schreiben, als noch Speicherplatz vorhanden ist.Bei Streaming-Protokollen wie TCP können Sie Ihren Puffer auf eine beliebige Größe einstellen. Es werden jedoch gemeinsame Werte mit Potenzen von 2 wie 4096 oder 8192 empfohlen.
Wenn mehr Daten als Ihr Puffer vorhanden sind, werden diese einfach für Ihren nächsten Aufruf im Kernel gespeichert
recv
.Ja, Sie können Ihren Puffer weiter vergrößern. Sie können eine Aufnahme in die Mitte des Puffers machen, beginnend mit dem Versatz
idx
. Sie würden Folgendes tun:quelle
Wenn Sie einen
SOCK_STREAM
Socket haben, werdenrecv
nur "bis zu den ersten 3000 Bytes" vom Stream abgerufen. Es gibt keine klare Anleitung, wie groß der Puffer sein soll: Das einzige Mal, wenn Sie wissen, wie groß ein Stream ist, ist, wenn alles erledigt ist ;-).Wenn Sie einen
SOCK_DGRAM
Socket haben und das Datagramm größer als der Puffer ist,recv
füllt es den Puffer mit dem ersten Teil des Datagramms, gibt -1 zurück und setzt errno auf EMSGSIZE. Wenn das Protokoll UDP ist, bedeutet dies leider, dass der Rest des Datagramms verloren geht - ein Teil dessen, warum UDP als unzuverlässiges Protokoll bezeichnet wird (ich weiß, dass es zuverlässige Datagrammprotokolle gibt, aber sie sind nicht sehr beliebt - ich konnte nicht Nennen Sie einen in der TCP / IP-Familie, obwohl Sie letzteres ziemlich gut kennen ;-).Um einen Puffer dynamisch zu vergrößern, weisen Sie ihn zunächst zu
malloc
und verwenden Sie ihnrealloc
nach Bedarf. Aber das hilft Ihnenrecv
leider nicht bei einer UDP-Quelle.quelle
Für
SOCK_STREAM
Sockets spielt die Puffergröße keine Rolle, da Sie nur einige der wartenden Bytes abrufen und bei einem nächsten Aufruf mehr abrufen können. Wählen Sie einfach die Puffergröße aus, die Sie sich leisten können.Für
SOCK_DGRAM
Socket erhalten Sie den passenden Teil der Wartemeldung und der Rest wird verworfen. Sie können die Größe des wartenden Datagramms mit dem folgenden ioctl erhalten:Alternativ können Sie
MSG_PEEK
undMSG_TRUNC
Flags desrecv()
Aufrufs verwenden, um die Größe des wartenden Datagramms zu erhalten.Sie müssen
MSG_PEEK
die wartende Nachricht einsehen (nicht empfangen) - recv gibt die tatsächliche, nicht abgeschnittene Größe zurück. und Sie müssenMSG_TRUNC
Ihren aktuellen Puffer nicht überlaufen lassen.Dann können Sie nur
malloc(size)
den realen Puffer und dasrecv()
Datagramm.quelle
malloc()
einen Puffer von 64 KB benötigen, ist dies nicht erforderlichMSG_TRUNC
?SOCK_DGRAM
ist nicht nur UDP.Es gibt keine absolute Antwort auf Ihre Frage, da die Technologie immer implementierungsspezifisch sein muss. Ich gehe davon aus, dass Sie in UDP kommunizieren, da die Größe des eingehenden Puffers kein Problem für die TCP-Kommunikation darstellt.
Gemäß RFC 768 kann die Paketgröße (einschließlich Header) für UDP zwischen 8 und 65.515 Byte liegen. Die ausfallsichere Größe für den eingehenden Puffer beträgt also 65 507 Byte (~ 64 KB).
Es können jedoch nicht alle großen Pakete ordnungsgemäß von Netzwerkgeräten weitergeleitet werden. Weitere Informationen finden Sie in der vorhandenen Diskussion:
Was ist die optimale Größe eines UDP-Pakets für maximalen Durchsatz?
Was ist die größte sichere UDP-Paketgröße im Internet?
quelle
16kb ist ungefähr richtig; Wenn Sie Gigabit-Ethernet verwenden, kann jedes Paket eine Größe von 9 KB haben.
quelle