Forum: PC-Programmierung Windows Socket: - Wieviel Bytes im Puffer


von Nero (Gast)


Lesenswert?

Hallo!

Ich habe eine kleines Programm, das Daten von einem Socket abholt.
Das funktioniert auch soweit ganz gut, sofern ich immer alle Daten mit 
der recv-Funktionen abholen kann, wie auch im Empfangspuffer drin 
stecken. Ist mein Puffer jedoch noch volltändig abgearbeitet und kann 
weniger Bytes aufnehmen, wird meine Receive-Funktion nur einmal 
aufgerufen. Die Bytes im Eingangspuffer verbleiben dort, bis auch der 
überläuft.

Wie bekomme ich nach dem Aufruf der recv-Funktion heraus, wieviele Bytes 
noch im Puffer bzw. zumindest ob noch Daten im Eingangspuffer sind?

Danke & Gruß
Nero

von Patrick-Oliver S. (patrick-oliver)


Lesenswert?

Dafür ist das Protokoll zuständig.
Z.B. beschreibt HTTP-Protokoll die Header-Zeile CONTENT-LENGTH, womit 
festgelegt wird, wie viele Bytes im Request-Body stehen.
Ansonsten nutze ich (*nix) epoll oder select mit Timeouts um 
herrauszufinden, ob ein Client noch etwas schicken möchte.

von Peter II (Gast)


Lesenswert?

Nero schrieb:
> Wie bekomme ich nach dem Aufruf der recv-Funktion heraus, wieviele Bytes
> noch im Puffer bzw. zumindest ob noch Daten im Eingangspuffer sind?

gar nicht, man ruft es einfach immer wieder auf, wenn man noch mehr 
daten haben will.

von Nero (Gast)


Lesenswert?

Patrick-Oliver Scheinert schrieb:
> Z.B. beschreibt HTTP-Protokoll die Header-Zeile CONTENT-LENGTH, womit
> festgelegt wird, wie viele Bytes im Request-Body stehen.

Da werden geräte Äpfel mit Birnen verglichen.
Um einen HTTP-header parsen zu können müsste auch dieser erstmal 
volltändig empfangen werden. Wenn ich allerdings von dem auch nur die 
ersten 80 Bytes empfange, komme ich auch nicht weiter.

Peter II schrieb:
> gar nicht, man ruft es einfach immer wieder auf, wenn man noch mehr
> daten haben will.

Pollen!? Unschön!

von Peter II (Gast)


Lesenswert?

Nero schrieb:
>> gar nicht, man ruft es einfach immer wieder auf, wenn man noch mehr
>> daten haben will.
>
> Pollen!? Unschön!

nein nicht pollen. read blockiert und pollt nicht. Man kann auch nicht 
blockierend arbeiten dann muss man mit select oder poll arbeiten - auch 
das ist aber kein pollen.

von Jojo S. (Gast)


Lesenswert?

recv() liefert ja zurück wieviele bytes gelesen wurden. Man muss also in 
einer Schleife solange lesen bis man die Sollanzahl bekommen hat. Wenn 
man 1000 Bytes erwartet kann man ausserdem nicht davon ausgehen das man 
die sofort am Stück bekommt, die können auch in kleineren Häppchen 
eintreffen. Ausserdem kann recv() die Anzahl 0 zurückliefern was dann 
bedeutet das der Gegner nicht mehr mitspielen will und die Verbindung 
beendet hat. recv() kann man bei den meisten OS auf blockierend oder 
nicht blockierend schalten, sollte man auch berücksichtigen.
Als nächste Hürde kann man auch nicht davon ausgehen das eine Verbindung 
immer ordentlich geschlossen wird, wenn der Sender sich irgendwo 
abklemmt kriegt der Empfänger das nicht mit wenn man nicht einen 
zyklischen Watchdog in die Übertragung einbaut.

von Udo S. (urschmitt)


Lesenswert?

Über was für einen Socket reden wir? TCP?
Bei TCP kannman sich nie verlassen mit einem Call alle Daten zu bekommen 
die auf der anderen Seite reingesteckt wurden.
Da die darunter liegenden Schichten versuchen die Übertragung zu 
optimieren, können immer erst mal Teile der Daten ankommen.

Du solltest also
1. Wissen wie viele Bytes übertragen werden. Dafür ist dein eigenes 
Protokoll zuständig. Am besten du sendest zu Beginn die Anzahl der 
folgenden Datenbytes
2. Solange receive aufrufen, bis alle Daten da sind
3. immer den returncode von receive prüfen, denn dort steht drin wie 
viele Bytes empfangen wurden.

Man kann sich NIE darauf verlassen.
Mir ist es einmal passiert daß selbst beim receive eines 2 Byte Wertes 
beim ersten Aufruf nur ein Byte empfangen wurde. Das Problem konnte 
natürlich nur beim Kunden nachgestellt werden und hat uns viel 
Kopfzerbrechen bereitet bis der Fehler gefunden wurde.

von Patrick-Oliver S. (patrick-oliver)


Lesenswert?

Nero:
> Da werden geräte Äpfel mit Birnen verglichen.
> Um einen HTTP-header parsen zu können müsste auch dieser erstmal
> volltändig empfangen werden. Wenn ich allerdings von dem auch nur die
> ersten 80 Bytes empfange, komme ich auch nicht weiter.

Dazu habe ich folgendes geschrieben:
> Dafür ist das Protokoll zuständig.
Im Beispiel HTTP weiß man dank des Protokolls (siehe RFC), wie die erste 
Zeile auszusehen hat und wie der HTTP-Header beendet wird.
Also lese ich solange, wie es das Protokoll verlangt.
So schwer ist das gar nicht und wie gesagt, es ist ein Beispiel!

Wenn man nicht weiß wieviele Daten gesendet werden, kann man nur endlos 
lesen.
Dazu blockiert recv. Will man das nicht, nutzt man select, poll, epoll 
... oder arbeitet mit nicht blockierenden Sockets.

von Udo S. (urschmitt)


Lesenswert?

Patrick-Oliver Scheinert schrieb:
> Dazu habe ich folgendes geschrieben:
>> Dafür ist das Protokoll zuständig.
> Im Beispiel HTTP weiß man dank des Protokolls (siehe RFC), wie die erste
> Zeile auszusehen hat und wie der HTTP-Header beendet wird.

Das ist völlig richtig.
Allerdings zeigt die Frage, daß der TO noch nicht so viel Erfahrung hat 
und sehr wahrscheinlich kein so komplexes Protokoll wie HTTP 
implementieren will. Entweder er weiss, daß seine Gegenstelle immer n 
Bytes sendet, oder er soll in den ersten beiden Bytes die Länge der 
Daten übertragen.
Dann aber bitte auf allen Systemen beachten welches Byte eines 2 Byte 
Werts zuerst gesendet wird.
Am besten net-byte-order nutzen (Big endian) also erst das höherwertige 
Byte übertragen.

von Nero (Gast)


Lesenswert?

Udo Schmitt schrieb:
> Allerdings zeigt die Frage, daß der TO noch nicht so viel Erfahrung hat
Richtig erkannt! ;)

Nun aber zu den ganzen Antworten:
Wissen wieviel Bytes kommen, egal wie das in einem Protokoll detektiert 
sind doch alles höhere Schichten?!?

Es geht darum, dass der Socket meldet "Daten verfügbar".
Diese liegen im Eingangspuffer des Sockets. - Verwaltet vom 
Betriebssystem.
Wie viele Bytes empfangen wurden weiß ich (noch) nicht. Annahme es sind 
100 Bytes.
"Mein" Empfangspuffer (CHAR ARRAY) hat auch nur eine begrenzte Größe, 
sagen wir 150 Bytes.
Jetzt ist eine vorangegangene Nachricht noch nicht abgearbeitet und 
belegt 90 Bytes vom Puffer. Ich hab noch 60 frei.
Beim Aufruf der recv-Funmktion kann ich sagen, dass er bitte nur "60" 
Bytes einlesen soll, was mir beim Rückgabewert auch mitgeteilt wird.
Von den 40 Rest weiß ich aber nichts ...
und da der Receive-Event abgearbeitet ist, kommt er auch nur ein mal.

von Peter II (Gast)


Lesenswert?

Nero schrieb:
> Von den 40 Rest weiß ich aber nichts ...
> und da der Receive-Event abgearbeitet ist, kommt er auch nur ein mal.

Sag doch erst mal woher du das Receive-Event hast. Im normales C gibt es 
soetwas eigentlich nicht. Dort verwenden man select, poll, WaitForObject 
usw und diese Melden einfach wieder das immer noch Daten da sind.

von mar IO (Gast)


Lesenswert?

Nero schrieb:
> Von den 40 Rest weiß ich aber nichts ...

Kann es sein, dass WSAGetLastError() WSAEMSGSIZE dabei zurück gibt, also 
sich noch Daten im Buffer befinden???

Quelle 
:http://msdn.microsoft.com/de-de/library/windows/desktop/ms740121(v=vs.85).aspx

Nero schrieb:
> Wie bekomme ich nach dem Aufruf der recv-Funktion heraus, wieviele Bytes
> noch im Puffer bzw. zumindest ob noch Daten im Eingangspuffer sind?

Iwie kann man wohl rausfinden wie viel im Buffer steht. Das kann sich 
aber ganz schnell ändern... Wenn der return-Wert gleich deiner 
bereitgestellten Buffergröße ist, dann musst Du noch mal die Funktion 
aufrufen. Wenn recv()  0 liefert, dann legen z.Z. keine Daten im Buffer 
an.

von Peter II (Gast)


Lesenswert?

mar IO schrieb:
> Iwie kann man wohl rausfinden wie viel im Buffer steht. Das kann sich
> aber ganz schnell ändern... Wenn der return-Wert gleich deiner
> bereitgestellten Buffergröße ist, dann musst Du noch mal die Funktion
> aufrufen

wenn jetzt aber nichts mehr drin ist, dann blockiert ist.

Man müsste erst mal etwas Quellcode sehen, damit man hier weiter helfen 
kann. Ich habe fast die Befürchtung das es um CLI geht.

von bluppdidupp (Gast)


Lesenswert?

mar IO schrieb:
> Kann es sein, dass WSAGetLastError() WSAEMSGSIZE dabei zurück gibt, also
> sich noch Daten im Buffer befinden???

Das betrifft nur UDP. Der Fehler wird geworfen wenn das "Paket" nicht in 
den bei recv() als Parameter angegebenen Puffer passt.
----
Die Anzahl der per recv() unmittelbar abrufbaren Bytes kann man mit
ioctlsocket und FIONREAD auslesen.
Wenn man vermeiden will das recv() blockiert, geht man aber eigentlich 
eher anders vor: Man kann z.B. select() mit nem geringen timeout nehmen 
oder auf WSAAsyncSelect / non-blocking Sockets zurückgreifen.
Oder man lässt es blockieren, aber in einem eigenen Thread.

von mar IO (Gast)


Lesenswert?

Peter II schrieb:
> wenn jetzt aber nichts mehr drin ist, dann blockiert ist.

Wenn er so eingestellt ist, dann schon...

bluppdidupp schrieb:
> mar IO schrieb:
>> Kann es sein, dass WSAGetLastError() WSAEMSGSIZE dabei zurück gibt, also
>> sich noch Daten im Buffer befinden???
>
> Das betrifft nur UDP. Der Fehler wird geworfen wenn das "Paket" nicht in
> den bei recv() als Parameter angegebenen Puffer passt.

Ich habe jetzt kurz die Doku dazu überflogen und da steht "als Beispiel 
UDP".  Weil ich es selber ned weiß, ist das wirklich so, dass das nur 
bei UDP funktioniert?

Neben select() kann man auch WSAPoll() benützten, soweit ich das in 
Erinnerung habe...

Was auch eine schöne Methode ist, sich einen Callback einzurichten, der 
immer aufgerufen wird, wenn neue Daten anstehen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.