Hallo zusammen,
ich versuche momentan mit der Methode
1
rc=recv(s,recvBuf,bufferLength,0);
die Antwort von einem Server zu empfangen. Nur das Problem ist, die
Antwort kommt in mehreren Paketen...
Wie schaffe ich es, dass erst alles empfangen wird und dann erst der
Code weiter abgearbeitet wird?
Wenn ich das in eine Schleife packe, bleibt der Code irgendwann in der
recv() Methode stehen, da diese ja blockiert.
1
/* Auf die Antwort des Servers warten */
2
do{
3
rc=recv(s,recvBuf,bufferLength,0);
4
5
if(rc>0){
6
/* String kopieren */
7
for(inti=0;i<=rc;i++){
8
strIn+=recvBuf[i-1];
9
}
10
}
11
}while(rc>0);
Ich habe gelesen man kann diese "non-blocking" machen aber verstehe
nicht ganz wie!?
Ich hoffe es kann mir jemand bei dem Problem helfen!
Gruß Kilian
Kilian K. schrieb:> Wie schaffe ich es, dass erst alles empfangen wird und dann erst der> Code weiter abgearbeitet wird?
Was bedeutet "alles"? Wenn der Server jede Sekunde 1 Byte sendet für die
nächsten 10 Jahre, wann soll deine Empfangsroutine beenden?
Kilian K. schrieb:> Wie schaffe ich es, dass erst alles empfangen wird
Was ist "alles"?
Du brauchst ja irgendein Kriterium um zu wissen, wann der Server
"alles" gesendet hat.
Entweder
- du kennst vorab die Länge des gesamten Datensatzes, oder
- du erkennst das Ende des Datensatzes an einem speziellen Byte oder
Schlüsselwort, oder
- der Server schließt die Verbindung nach erfolgter Datenübertragung.
Vielleicht gibt es auch noch weitere Endekriterien.
Allen gemeinsam ist, dass du in deiner Client-Software eine Schleife so
lange drehen lässt, bis dieses Kriterium erfüllt ist.
Ob du das blockierend machst oder nicht, ist wieder eine andere Frage.
Nichtblockierend bedeutet einfach nur, dass der recv-Aufruf immer sofort
zurückkehrt, auch wenn keine neuen Daten empfangen wurden. Das gibt dir
die Möglichkeit, in der Schleife noch weitere Dinge abzuarbeiten.
In der Antwort sind immer 7 Semikolons enthalten. Das könnte ja dann das
Kriterium sein. Das hatte ich auch schon versucht aber nach dem Paket
mit dem 6. Semikolon blieb das Prgramm in der recv() Methode stehen...
Kilian K. schrieb:> In der Antwort sind immer 7 Semikolons enthalten. Das könnte ja dann das> Kriterium sein. Das hatte ich auch schon versucht aber nach dem Paket> mit dem 6. Semikolon blieb das Prgramm in der recv() Methode stehen...
dann kommt auch kein Zeichen mehr. Sicher das du nicht verzählt hast?
du kannst vorher ein select oder poll auf den Socket machen. Wenn das
etwas liefert, kannst du sicher sein, das das recv nicht blockiert.
Die kurze Antwort ist, weder TCP noch UDP sagen dir wie viele Daten da
kommen oder bieten dir irgendeine Möglichkeit an Daten"pakete"
gegeneinander abzugrenzen. Das musst du auf einer höheren Protokollebene
machen, zum Beispiel indem du zuerst einen Header sendest, in dem die
Anzahl der Bytes steht die danach noch gelesen werden müssen. Zumindest
TCP garantiert dir dann zumindest dass all diese Bytes auch ankommen.
Du musst die dem recv übergebene Pufferlänge anpassen.
Wenn Du vorher nicht weisst, wie viele Daten noch kommen sollen, musst
Du entweder Byte-für-Byte lesen oder Dir ein anderes Protokoll
überlegen, bei dem Du dieses Wissen hast.
Kilian K. schrieb:> In der Antwort sind immer 7 Semikolons enthalten. Das könnte ja dann das> Kriterium sein.
Wenn das letzte Semikolon das Ende der Antwort markiert, ja.
> Das hatte ich auch schon versucht aber nach dem Paket mit dem 6.> Semikolon blieb das Prgramm in der recv() Methode stehen...
Hast du denn einen TCP- oder einen UDP-Socket? Hast du den Sender auch
geschrieben, oder ist der gegeben?
Peter II schrieb:> du kannst vorher ein select oder poll auf den Socket machen. Wenn das> etwas liefert, kannst du sicher sein, das das recv nicht blockiert.
Das ist falsch.
Sven B. schrieb:> Die kurze Antwort ist, weder TCP noch UDP sagen dir wie viele Daten da> kommen oder bieten dir irgendeine Möglichkeit an Daten"pakete"> gegeneinander abzugrenzen.
Bei UDP kann man durchaus Pakete abgrenzen. UDP ist ein
Datagramm-orientiertes Protokoll.
Rolf M. schrieb:> Peter II schrieb:>> du kannst vorher ein select oder poll auf den Socket machen. Wenn das>> etwas liefert, kannst du sicher sein, das das recv nicht blockiert.>> Das ist falsch.
was soll daran falsch sein?
Naja, es stimmt eben nicht, zumindest unter Linux. Die man-Page sagt bei
mir:
"Under Linux, select() may report a socket file descriptor as "ready for
reading", while nevertheless a subsequent read blocks. This could
for example happen when data has arrived but upon examination has wrong
checksum and is discarded. There may be other circumstances in which a
file descriptor is spuriously reported as ready. Thus it may be safer
to use O_NONBLOCK on sockets that should not block."
Rolf M. schrieb:> Naja, es stimmt eben nicht, zumindest unter Linux. Die man-Page sagt bei> mir:
seht aber unter "Bugs"
kann man nur hoffen das es mal behoben wird, bei poll steht nichts
davon. Auch bei MS steht nicht davon.
Naja wenigsten werden die Bugs bei Linux dokumentiert, statt behoben.
Interessant. Ich dachte bisher, dass "spurious readiness notifications"
Teil des Standards sind. Posix sagt allerdings: "A descriptor shall be
considered ready for reading when a call to an input function with
O_NONBLOCK clear would not block..."
http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.htmlPeter II schrieb:> bei poll steht nichts davon
Bei mir steht da: "See the discussion of spurious readiness
notifications under the BUGS section of select(2)".
Mikro 7. schrieb:> Außerdem...>> Kilian K. schrieb:> /* String kopieren */>> for (int i = 0; i <= rc; i++) {>> strIn += recvBuf[i-1];>> }> ...was passiert bei i=0?
Das hatte ich mir mal von einer Seite kopiert um es zu testen.
Habe es auch noch weiter versucht aber irgendwie will es noch nicht so
wirklich funktionieren.
Mein aktueller Stand ist so:
Mein Problem ist, zurzeit werden 260 Byte ausgelesen und in recvBuf
gespeichert. Es wird aber erkannt, dass es noch mehr Daten zum auslesen
gibt aber der Rest wird nicht abgespeichert... Es wird also weiter
ausgelesen aber es bleiben immer nur die 260 Byte in recvBuf.
recvBuf erstelle ich so:
1
#define BUFFER_LENGTH 10000
2
3
char*recvBuf;
4
recvBuf=newchar[BUFFER_LENGTH];
Rolf M. schrieb:> Hast du denn einen TCP- oder einen UDP-Socket?
Mein Programm hat einen TCP- und UDP-Socket wobei ich in diesem Beispiel
mit einem TCP-Socket arbeite!
Sven B. schrieb:> Zumindest> TCP garantiert dir dann zumindest dass all diese Bytes auch ankommen.
Nein. Auch bei TCP muß ein Timeout rein. Server können ausfallen,
Internetverbindungen abreißen und dergleichen. Daraufhin muß die
Software in einen Zustand versetzt werden, daß sie versucht, sich erneut
zu synchronisieren.
Im Falle mobiler Internetverbindungen tunlichst nicht einfach jede
Sekunde den Server kontaktieren, weil sonst das Datenvolumen anschwillt.
Dann nimmt man einen Backoff-Algorithmus.
Ach ja, man sollte auch über eine CRC für die Inhalte nachdenken. Die
TCP-Checksumme ist ein schlechter Witz.
Mikro 7. schrieb:> sizeof(recvBuf)?
Lese halt nicht jedes Byte einzelnd aus sondern immer 4...
Mikro 7. schrieb:> Was passiert bei i == readSize?
Hatte ich noch übersehen. Habe es in
1
for(inti=0;i<readSize;i++){
geändert.
Mikro 7. schrieb:> Für den else-Zweig gibt es nichts zu beachten?
Ne, eigentlich nicht. Will ja nur die Semikolons haben, der Rest ist ja
egal...
Kilian K. schrieb:> Mein Problem ist, zurzeit werden 260 Byte ausgelesen und in recvBuf> gespeichert. Es wird aber erkannt, dass es noch mehr Daten zum auslesen> gibt aber der Rest wird nicht abgespeichert... Es wird also weiter> ausgelesen aber es bleiben immer nur die 260 Byte in recvBuf.
Auf einen ersten Blick sollte dein Code trotz der Bugs funktionieren,
wenn denn tatsächlich immer 7 Semikolons innerhalb von BUFFER_LENGTH
enthalten sind, readSize auf 0 initialisiert ist, und recv() weder EOF
noch Fehler liefert. Kompletter Client/Server Code wäre hilfreich,
reduziert auf das Fehlerszenario.
Kilian K. schrieb:> Mikro 7. schrieb:>> sizeof(recvBuf)?>> Lese halt nicht jedes Byte einzelnd aus sondern immer 4...
Warum "tarnen" mit sizeof(recvBuf)?
Bug: Was passiert wenn bereits BUFFER_LENGTH Daten gelesen wurden?
> Mikro 7. schrieb:>> Für den else-Zweig gibt es nichts zu beachten?>> Ne, eigentlich nicht. Will ja nur die Semikolons haben, der Rest ist ja> egal...
Naja, EOF und Fehler sollten imho anders behandelt werden als durch
"Endlosschleife".
Kilian K. schrieb:> Mikro 7. schrieb:>> sizeof(recvBuf)?>> Lese halt nicht jedes Byte einzelnd aus sondern immer 4...
Äh, ja. Hoffe, das war ein Scherz.
Kilian K. schrieb:> So funktioniert es anscheinend... So wie es aussieht empfange ich alles> und es wird auch alles augegeben!
Das ist aber Zufall, da recv() wahrscheinlich alle Zeichen in einem
Aufruf lesen konnte.
recv() addiert bei jedem Aufruf die neu empfangene Bytes am "Ende" vom
revBuf. So weit so gut.
Die for()-Schleife aber fängt immer wieder von ganz vorne an nach
Semicolons zu suchen und addiert die zum Resultat hinzu. Wenn also im 1.
recv() 4 Semicolons gefunden wurden, und im 2. keine wird trotzdem
semicolons auf 8 hochgezählt und die Rountine abgebrochen obwohl erst
4 Semicolons gelesen wurden.
Eric B. schrieb:> Kilian K. schrieb:>>> So funktioniert es anscheinend... So wie es aussieht empfange ich alles>> und es wird auch alles augegeben!>> Das ist aber Zufall, da recv() wahrscheinlich alle Zeichen in einem> Aufruf lesen konnte.> recv() addiert bei jedem Aufruf die neu empfangene Bytes am "Ende" vom> revBuf. So weit so gut.> Die for()-Schleife aber fängt immer wieder von ganz vorne an nach> Semicolons zu suchen und addiert die zum Resultat hinzu. Wenn also im 1.> recv() 4 Semicolons gefunden wurden, und im 2. keine wird trotzdem> semicolons auf 8 hochgezählt und die Rountine abgebrochen obwohl erst> 4 Semicolons gelesen wurden.
Aber die Variable wird doch vor dem Einlesen wieder zurückgesetzt.
Man kann es aber natürlich auch so machen:
Kilian K. schrieb:> Rolf M. schrieb:>> Äh, ja. Hoffe, das war ein Scherz.>> Haha leider nicht. Erstaunlicherweise bekomme ich damit 4 Byte statt nur> einem ausgelesen :D
Ja, weil du immer soviele Bytes liest, wie ein Zeiger groß ist. Ist wohl
ein 32-Bit-Programm. In 64 Bit würdest du immer 8 Bytes auf einmal
lesen.