Empfangspuffer für TCP- bzw- UDP-Sockets dimensionieren.

Tikonteroga

Erfahrenes Mitglied
Hallo,

ich möchte ein Protokol implementieren, dass man sowohl über TCP als auch über UDP übertragen können soll.

Über die bedingte Kompilierung soll dann entschieden werden können, ob TCP oder UDP verwendet wird.

Für die Implementierung möchte ich SOCKETS (winsock2.h) verwenden.

Aktuell stehe ich vor dem Problem, dass ich für das C-Modul, innerhalb dem die SOCKET-Aufrufe gekapselt werden, einen statischen Empfangspuffer implementieren möchte.

Code:
static char buffer[SIZE];

In der Dokumentation ist leider nicht dokumentiert, wieviele Daten im Höchstfall bei TCP oder UDP übertragen werden können.

Der einzigste Anhaltspunkt, den ich habe, ist dass die Anzahl der empfangenen Bytes als int zurückgegeben wird. Ich könnte also INT_MAX verwenden. Das wären dann halt 2 GB... Ich würde hier schon gerne Speicher einsparen, möchte aber auch immer alle Daten im Empfangspuffer speichern können.

Grüße

Tikonteroga
 
Hi

was haben zurzeit alle mit diesem static in C?

...
ich versteh nicht.
Was sind "alle Daten" und warum muss man die alle im Ram haben?

Und was erwartest du dir von optionalem UDP genau?

Bechreib einfach einmal, was du vorhast.
Was da übertragen werden soll, wozu,
was du dir aussuchen kannst und was nicht.
 
Hi

was haben zurzeit alle mit diesem static in C?

...
ich versteh nicht.
Was sind "alle Daten" und warum muss man die alle im Ram haben?

Und was erwartest du dir von optionalem UDP genau?

Bechreib einfach einmal, was du vorhast.
Was da übertragen werden soll, wozu,
was du dir aussuchen kannst und was nicht.

Also das Protokol, dass ich übertragen möchte, ist so spezifiziert, dass ich es über TCP oder UDP übertragen können muss.

Das Protokoll definiert Packete mit einem HEADER (4 Byte) und einem PAYLOAD (0..65535 Bytes). Der Header enthält die Length (2 Byte) und einen Counter (2 Byte). Es ist möglich mehrere Packete im Payload von einem UDP-Packet oder einem TCP-Packet zu übertragen.

Length (2 Byte), Counter (2 Byte), Data (Length Byte)

Das "static" habe ich deshalb verwendet, weil über das C-Modul nur eine Verbindung möglich sein muss. Ansonsten hätte ich den Puffer in einem HANDLE verborgen. Ausserdem möchte ich zur Laufzeit möglichst keine größeren Speicherbereiche auf dem Stack oder dem Heap allokieren, damit der Speicherverbrauch über der Zeit keine großen Sprünge macht. Den Puffer benötige ich über die gesamte Laufzeit des Programms, deshalb kann dieser permanent bestehen.
 
Nochmal eine Verständnisfrage hinterher. Aktuell verwendet ich SOCK_STREAM bei TCP. So wie ich das verstehe, können in dem Puffer den mir recv() zurückgibt mehrere Payloads aus mehreren TCP-Packeten enthalten sein.

Ist es denn möglich, dass ich mit einem recv() nur die Payload von einem TCP-Packet erhalten kann? Und mit dem nächsten Aufruf von recv() dann den Payload vom nächsten TCP-Packet?
 
Zuletzt bearbeitet:
Also ich glaub ich war jetzt auf dem falschen weg.

Ich glaube sinnvoll wäre es. Wenn ich zuerst den 4 Byte Header lese. Dann habe ich die Length der Daten. Dann lese ich Length Bytes an Daten. Und dann den nächsten 4 Byte Header usw. Als Puffer für die Daten verwende ich 65535 Bytes.
 
Hallo Tikonteroga

Zu zweitletzten Posting: Es ist möglich, dass in recv mehrere Pakete kommen, es ist auch möglich, dass nur ein Teil eines Pakets kommt. recv gibt einfach ein paar Bytes zurück, sobald etwas vorhanden ist, wie viel kannst du nicht sagen, hat auch nichts damit zu tun, wie viel schon ge-send-et wurde.

Wie du sagtest ist die beste Variante zuerst so lange zu recv-en bis du 4 Bytes zusammen hast für den Header, anschliessend dann die Länge an Daten auslesen. Der statisch allozierte Buffer ist eine Möglichkeit, wenn bei deiner Applikation Speicherallokationen kritisch sind, ansonsten empfehle ich dir einen passend allozierten Speicherblock mit malloc zu verwenden, da du diesen dann auch ausserhalb des Scopes verarbeiten kannst.

Viele Grüsse
Cromon
 
Zu dem "Counter" im Header: Kann es sein,
dass du für UDP die Verlässlichkeitssachen selbst implementieren musst?
Oder ist das bei den Daten egal?

Was das konkret wäre: Erkennen von mehrfachen gleichen Paketen,
fehlenden Paketen, und fehlerhafter Reihenfolge.
Und zwar UDP-Pakete, nicht deine Protokollpakete.
Nur mit dem counter allein kommst du so nicht weit.
 
Hallo Tikonteroga

Wie du sagtest ist die beste Variante zuerst so lange zu recv-en bis du 4 Bytes zusammen hast für den Header, anschliessend dann die Länge an Daten auslesen. Der statisch allozierte Buffer ist eine Möglichkeit, wenn bei deiner Applikation Speicherallokationen kritisch sind, ansonsten empfehle ich dir einen passend allozierten Speicherblock mit malloc zu verwenden, da du diesen dann auch ausserhalb des Scopes verarbeiten kannst.

Hallo,

danke für die Rückmeldung. Ich habe jetzt eine Funktion implementiert, die pro Aufruf ein Packet aus dem Stream liest. Dabei muss der Auftrufer der Funktion den Puffer den in Form von einer Struktur bereitstellen.

Danke nochmal.
 
Zu dem "Counter" im Header: Kann es sein,
dass du für UDP die Verlässlichkeitssachen selbst implementieren musst?
Oder ist das bei den Daten egal?

Was das konkret wäre: Erkennen von mehrfachen gleichen Paketen,
fehlenden Paketen, und fehlerhafter Reihenfolge.
Und zwar UDP-Pakete, nicht deine Protokollpakete.
Nur mit dem counter allein kommst du so nicht weit.

Also das Protokol definiert zum Einen eine synchrone Request-Response-Kommunikation. Wenn auf ein Request nicht innerhalb einer bestimmten Zeit (timeout) das passende Response nicht empfangen wird, gibt je nach Request eine Fehlerbehandlung. Das kann z. B. ein Retry sein.

Es gibt auch eine Producer-Consumer-Kommunikation, bei dem zyklisch eine Sequenz von Packeten, die innerhalb des Payloads nummeriert sind und die man auch durch Protokolinformationen von den Requests bzw. Responses unterscheiden kann.
 
Hallo,

mir ist wohl noch ein weiteres Problem aufgefallen.

Ich habe den SOCKET folgendermaßen erstellt.

Code:
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

Ich muss über das TCP-Packet ein bestimmtes Protokoll aufsetzen, bei dem ein Packet folgendermaßen aufgebaut ist.

Length (2 Bytes)
Counter (2 Bytes)
Data (Length Bytes)

Dabei kann ein TCP-Packet mehrere solcher Packete enthalten.

Jetzt meine Fragen.

1. Habe ich mit SOCK_STREAM überhaupt einen Einfluss darauf, welche Daten innerhalb von einem TCP-Packet versendet werden?
2. Falls nein, muss ich dann einen Packet-orientierten Typ anstelle von SOCK_STREAM auswählen?
3. Wieviele Bytes an Daten, kann ich in einem TCP-Packet versenden? Kann ich den Wert für die maximale Anzahl an Byte irgendwie abrufen bzw. ändern?
 
Zurück