read/write bei Sockets
-
Ich habe einige Verständnisfragen zu den besagten Funktionen.
Es kann im Zusamenhang mit read und sockets passieren, dass der Puffer im Kernel voll ist und noch weitere Daten vom Client gesendet wurden. Somit muss ich den Kernel-Puffer mehrmals auslesen. Also zum Beispiel: Client sendet 8000 Byte, in den Kernelpuffer passen aber nur 2048. Nun muss ich mind. 4 mal read aufrufen, wenn ich als Puffergröße 2000 oder beliebig größer angegeben habe. Soweit richtig?
Wie mache ich das nun am elegantesten, also so wenig wie möglich read/write aufrufen, aber trotzdem so portabel, dass es auf allen Unices läuft? Nach meinem Verständnis muss ich solange read aufrufen, bis 0(EOF) zurückgegeben wurde, oder bin ich auf dem falschen Weg?
In dem Buch von Stevens wird eine eigene Funktion entwickelt die immer byteweise den Puffer ausließt. Wo liegen die Vorteile dieser Variante?
Vielen Dank im voraus!
-
Versuch mal send und recv, dann sollte es klappen
-
Am besten schreibst Du dir eine eigene Recv/Read Funktion ....
Unzwar setzt du bei dem zusendenen Buffer vorne ein 2 oder 4 Byte grosses prefix rein. Dieses Prefix sagt aus wie gross der gesammtbuffer ist.Das bedeutet das Du auf der empfangsseite genau weisst wieviel du bekommen hast und wieviel noch zu empfangen ist. Das auslesen von zeichen oder Record weise hat seine vorteile auf den verschieden Plattformen. Wenn Du auf einer Recordverarbeitenden Platform bist ( OS/390 ) dann macht das Record(Satz) weise empfangen und senden mehr sinn aber ich kann dir morgen oder heute abend noch eine Tabelle reisetzten die die genaue verarbeitung von Zeichen und bufferweise verdeutlicht. Ich hoffe ich konnte Dir ein wenig helfen und wenn du noch fragen hast zur RECV Routine kann ich Sie Dir ja schicken ...
-
spoensche schrieb:
Versuch mal send und recv, dann sollte es klappen
Danke, aber mein Wissensdurst möchte auch gestillt werden wo dieses Problem seine Urasache hat.
LEO 3 schrieb:
Das bedeutet das Du auf der empfangsseite genau weisst wieviel du bekommen hast und wieviel noch zu empfangen ist. Das auslesen von zeichen oder Record weise hat seine vorteile auf den verschieden Plattformen.
Danke, klingt interessant! Aber mein Problem würde weiterhin bestehen bleiben, wenn ein anderer Client mir Daten schickt, der nicht so ein Prefix mitsenden würde.
Das Problem was ich auch primär sehe ist folgendes:
while (read(fd, buffer, sizeof(buffer)) > 0){ ... }
Dieser Code ließt immer sizeof(buffer) Bytes aufeinmal. Wurden aber beim letzten Lesevorgang weniger Bytes als sizeof(buffer) gelesen, blockiert read. Dieses Problem könnte man halt, wie in dem Stevens Buch, durch byteweises lesen umgehen.
Aber ist das die einzige Möglichkeit, wenn ich keinen Einfluss auf den Client habe, der mir Daten sendet?
-
Socket-User schrieb:
Das Problem was ich auch primär sehe ist folgendes:
while (read(fd, buffer, sizeof(buffer)) > 0){ ... }
Dieser Code ließt immer sizeof(buffer) Bytes aufeinmal. Wurden aber beim letzten Lesevorgang weniger Bytes als sizeof(buffer) gelesen, blockiert read. Dieses Problem könnte man halt, wie in dem Stevens Buch, durch byteweises lesen umgehen.
Ne, da hast du man: read(2) falsch verstanden. read liest maximal n (in dem Fall sizeof(buffer)) bytes. Die Anzahl der gelesenen Bytes wird zurück geliefert. read blockiert eben nur, wenn keine Daten vorhanden sind und wartet auf einkommende Daten. Dafür gibt es aber Nonblocking Sockets. Naja, lies einfach ein wenig im Stevens weiter.
-
Socket-User schrieb:
Danke, klingt interessant! Aber mein Problem würde weiterhin bestehen bleiben, wenn ein anderer Client mir Daten schickt, der nicht so ein Prefix mitsenden würde.
Das geht halt nicht. Wenn deine Anwendung keine Größe mitschickt, kannst du nicht wissen, wie groß das Ding mal war.
-
Danke @all!
Ringding schrieb:
Das geht halt nicht. Wenn deine Anwendung keine Größe mitschickt, kannst du nicht wissen, wie groß das Ding mal war.
Wie läuft das denn zum Beispiel bei der Verbindung Browser->Webserver? Der Browser weiß ja nicht vorher wie groß die angeforderte Seite ist. Schickt der Webserver die Größe am Anfang mit?
kingruedi schrieb:
Naja, lies einfach ein wenig im Stevens weiter.
Werde ich machen!
Zuletzt noch eine Frage, die mir aus dem Stevens immer noch nicht ganz klar ist. Warum liest seine readn/writen Funktion immer nur ein Byte? Wo ist da der entscheidene Vorteil?
-
Socket-User schrieb:
Schickt der Webserver die Größe am Anfang mit?
Ja (fast immer).
Andernfalls liest der Browser einfach so lang, bis der Server den Socket schließt.
-
Socket-User schrieb:
Danke, aber mein Wissensdurst möchte auch gestillt werden wo dieses Problem seine Urasache hat.
in der paketfragmentierung.
-
Es gibt zwei Möglichkeiten festzustellen, ob Du alle Daten bekommen hast. Entweder der Client schließt am Ende die Verbindung, dann wird serverseitig ein eof erkannt, oder der Datenstrom ist so gestaltet, daß ein Ende erkannt wird. Anders geht es nicht.
Bei HTTP gibt es mehrere Varianten. Der Request wird mit einer Leerzeile beendet. Daran erkennt der Server, daß der Client alles geschickt hat. Bei einem POST-request muß der Client aber noch weitere Daten schicken. Dafür muß er im Header allerdings eine Zeile "Content-Length: xxx" angeben, damit der Server weiß, wie viele Bytes er zu empfangen hat.
Der Server kann es sich beim Reply einfacher machen. Er schickt die Antwort und macht ein close. Er benötigt die Verbindung zum Client ja nicht mehr. Das ist die klassische Variante. Das hat sich als nicht sehr performant erwiesen, da für jeden Request eine neue Verbindung aufgebaut werden muß. Daher hat man später im HTTP eine andere Variante namens Keep-Alive definiert.
Wenn der Client über einen bestimmten HTTP-Header signalisiert, daß er keep-alive kann, darf der Server auch keep-alive machen. Dazu muß er wieder im Header ein Content-Length angeben. Dann weiß der Client wieder, wann er mit dem read fertig ist und kann den Socket für den nächsten Request verwenden.
Übrigens, wenn Du C++ programmierst (wir sind hier ja auf www.c-plusplus.net), kannst Du eine der Zahlreichen Bibliotheken verwenden, wie z. B. socket++ oder meine cxxtools (unter www.tntnet.org zu finden).
Für HTTP nimmt man natürlich tntnet
Gruß
Tommi