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
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.
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.
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!
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.
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.
Ü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.
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.
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.
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.
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.
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.