recv() blockiert in Thread fast 1 Minute
-
Hallo,
Nachfolgend möchte ich mein Problem schildern:
Entwicklungsumgebung: MS Visual Studio 2003
Verwendete Sprache: C++
.Net erlaubt/verwendet: nein!
Betriebssystem auf dem entwickelt wird: Windows 2000Softwarekomponenten/Struktur (grobe Darstellung):
------------------ ------------------ -------------- | http-Server (2)| ------- | http-Server (1)| ------- | client (3) | ------------------ ------------------ -------------- | | |----------------------------------------------------- | (normaler Aufruf, z.Bsp. über Firefox)Thread-Struktur:
------------------------------------ | http-Server (1) | | -------- --------- | |----| T2 |------------| T1 |-|------- Socket Verbindung zu Clients | -------- --------- | -> mehrere Verbindungen möglich ------------------------------------ -> nutzt select()/accept() T1 ist der Haupt-Thread. Hier läuft der eigentliche Webserver und alle weiteren Programmkomponenten (es wurde aber nicht explizit für diese Funktionalität ein extra Thread gestartet – das Betriebssystem macht das doch aber automatisch oder?). Ein bestimmter Teil dieser Komponenten startet einen weiteren Thread T2 der ebenfalls eine Socketverbindung aufbaut – hier aber zum http-Server (2)!http-Server (1) und der Client (3) laufen lokal auf meinem Rechner. (2) ist über RJ45 lokal an meinen Rechner angeschaltet und befindet sich im selben IP-Adressen Bereich (192.168.0.x).
Ich möchte folgendes erreichen:
Mein Client (z.Bsp. Firefox-Browser) stellt eine Anfrage nach einer bestimmten Ressource an (1). (1) erhält diese Anfrage und sendet seinerseits eine http-Anfrage an (2) nach eben dieser Ressource. Nachdem (2) diese Anfrage erhalten hat wird die Antwort von (2) jetzt wieder zuerst an (1) und von (1) an (3) zurück gesendet.Ich habe ausschließlich Zugriff auf den Quellcode von (1). Der http-Server (2) steht weder unter meiner Kontrolle noch habe ich Möglichkeiten dort etwas zu verändern.
Rufe ich die Ressource von meinem Browser (3) direkt von (2) ab, so ist alles In Ordnung und die Anfrage dauert unter 1s. Leider muss ich später den "Umweg" über (1) gehen, da eine direkte Verbindung von (3) zu (2) technisch gesehen nicht mehr möglich/vorhanden sein wird.
Mein Problem ist folgendes:
(1) muss gleichzeitig Server, und auch Client sein (siehe T2 der seinerseits eine Socketverbindung aufbaut und an (2) Daten sendet + auf die Antwort wartet).
(1) verwaltet seine Verbindungen über accept() und select(). Das Funktioniert absolut fehlerfrei.
Das Problem ist, wenn ich über einen neu erzeugten Socket Daten (http-request) an (2) sende und anschließend auf die Antwort warte, blockiert recv() in (1) - also genauer gesagt im Thread T1 ca. 56s lang!!while (nTotalBytes < nBufferSize) { ... int nNewBytes = recv(nSocket, acReadBuffer+nTotalBytes,80000-nTotalBytes, 0); ... }Anschließend läuft die Schleife zum empfangen der Daten noch ein paar Mal durch und alle Daten wurden korrekt empfangen.
Auch das Auslagern der Socket-Anfrage in einen separaten Thread verhindert nicht das ewige blockieren der recv() Funktion!
Die angefragte Datenmenge beläuft sich auf ca. 20-40 KB.
Vielleicht kann mir jemand bei meinem Problem helfen, denn ich bin inzwischen ziemlich verzweifelt und mir fällt absolut keine Lösung ein.
Vielen Dank schonmal!MFG
Ps.: ich hoffe ich habe genug Hintergrundinfos geliefert damit auch jeder das Problem verstehen kann.
-
-
Danke für die schnelle Antwort!
C++ Entwickler schrieb:
Das Problem ist, wenn ich über einen neu erzeugten Socket Daten (http-request) an (2) sende und anschließend auf die Antwort warte, blockiert recv() in (1) - also genauer gesagt im Thread T1 ca. 56s lang!!
Ich glaube in http://support.microsoft.com/?scid=kb%3Ben-us%3B106479&x=10&y=14 geht es darum, das wenn man recv() auf dem gleichen Socket aufruft wo vorher schon send() gerufen wurde, wird blockiert. Oder habe ich da was falsch verstanden?
Ich erzeuge aber einen neuen Socket-Descriptor mit:
nSocket = socket(PF_INET, SOCK_STREAM, 0);Außerdem müssten die Daten auch sofort verfügbar sein, da http-Server (2) direkt an meinem Rechner über ein lokales Netz (crossover-Kabel) angeschlossen ist. Im Firefox ist die Anfrage ja auch super schnell...also die Daten müssten eigentlich sofort zur Verfügung stehen.
Desweiteren ist das recv() im Hauptprogramm schon abgeschlossen, da der Request vom client schon empfangen und ausgewertet worden ist (nur so kann ich ja herausfinden, das ich jetzt noch eine Anfrage an http-Server (2) senden muss).
Könnte das Problem auch damit zusammenhängen, das mein Puffer größer ist als die Menge der Daten die ich empfange? -> Also ich lese Daten (empfangen < puffer) und recv() "will" den puffer noch vollschreiben, aber es sind keine Daten mehr da...?
MFG
-
Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum WinAPI verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
C++ Entwickler schrieb:
...
Könnte das Problem auch damit zusammenhängen, das mein Puffer größer ist als die Menge der Daten die ich empfange? -> Also ich lese Daten (empfangen < puffer) und recv() "will" den puffer noch vollschreiben, aber es sind keine Daten mehr da...?Nein, daran kanns nicht liegen. recv liest eher zu wenig als zu viel.
Er liest also nicht bis der von Dir übergebene Puffer komplett voll ist.Vielleicht hat das irgendwas mit Authorisation am Webserver (2) zu tun!?
-
Er liest also nicht bis der von Dir übergebene Puffer komplett voll ist.
??
Mein Puffer kann ja nicht voll werden...ich habe einen 80 kb großen Puffer, es werden aber wohl niemals mehr als 20-40 kb Daten empfangen.Am Server (2) muss man sich Authorisieren, aber da es dort einen "festen" Zugang gibt und der sich auch nicht ändern wird, übergebe ich im request header:
const char* cRequest = "GET /xyz... HTTP/1.1\nHost: 192.168.0.253\nConnection: keep-alive\nAuthorization: Basic abcdefg....\r\n";Das sollte also nicht das Problem sein.
Durch debuggen habe ich herausgefunden, das die Daten in folgenden Häppchen empfangen werden: zuerst 17 Byte, anschließend 9216 Byte und zum Schluss der Rest...meistens etwas mehr als 10000 Byte (zusammen: >20000 Bytes).
Das merkwürdige ist ja, das er schon bei den ersten 17 Bytes blockiert und der Empfang der restlichen <20000 Bytes super schnell geht (praktisch sofort). Der Unterschied der Gesamtgröße der Daten kommt dadurch zu Stande, da ich ein Bild im image/jpeg Format anfordere (und dieses Bild ändert sich "öfters").
Ich hatte noch die Idee:
fcntl(nSocket,F_SETFL,O_NONBLOCK);zu verwenden, aber leider gibt es eine Fehlermeldung: error C3861: 'fcntl': Bezeichner wurde auch mit einer argumentbezogenen Suche nicht gefunden trotz eingebundener <fcntl.h>!
Bisher sieht meine recv() - Schleife so aus:
char acReadBuffer[80000]={0}; //80kB int nBufferSize(sizeof(acReadBuffer)); int nTotalBytes(0); while (nTotalBytes < nBufferSize) { int nNewBytes = recv(nSocket, acReadBuffer+nTotalBytes,80000-nTotalBytes, 0); if (nNewBytes == SOCKET_ERROR) { printf("\nerror while recieving Data!"); break; } else if (nNewBytes == 0) { printf("%d Bytes...", nTotalBytes); break; } nTotalBytes += nNewBytes; }Der Thread wird übrigens erzeugt mit:
myThread = 0; dwThreadId = 0; myThread = CreateThread( NULL, 0, xyz..., &xyz..., 0, &dwThreadId); if ( myThread == NULL) { ... }Irgendwie habe ich langsam keinerlei Idee mehr was ich noch tun könnte.
-
const char* cRequest = "GET /xyz... HTTP/1.1\r\nHost: 192.168.0.253\r\nConnection: keep-alive\r\nAuthorization: Basic abcdefg....\r\n\r\n";
-
Unter Windows heisst die Funktion ioctlsocket.
Aber was ist eigentlich das Problem?
Ist es...- du bist sicher dass der Server die Daten schneller liefert, und nur in deinem Programm irgendwas 1 min blockiert oder
- der Server braucht einfach 1 min bis er die Daten liefert, und du willst dass recv nicht blockiert?
Im 1. Fall kann ich dir keine Tips geben, sowas hatte ich noch nie.
Im 2. Fall kannst du den Socket mittels ioctlsocket auf nonblocking umschalten, damit sollte sich das lösen lassen.BTW: bist du sicher dass du keine Fehler beim Weiterleiten des Requests gemacht hast? Fehlt vielleicht ein abschliessendes CR-LF oder sowas? Das könnte erklären wieso es so lange dauert bis du Daten vom Server bekommst. Nämlich wenn dieser ein Timeout von ~1 min verwendet, und dann abbricht falls nixmehr kommt. Wenn der Server dann in dem Fall den Request trotzdem auswertet (was ohne weiteres möglich wäre wenn z.B. nur ein abschliessendes CR-LF fehlt), dann würde es erklären wieso der Server noch auf ein paar Bytes wartet, die Anfrage dann aber (nach dem Timeout) trotzdem funktioniert.
Weiss nicht, ist ein Schuss ins Blaue, aber sonst fällt mir dazu nichtmehr viel ein.p.S.: hehe, ich blindes Huhn. Genau das (fehlendes CR-LF) wollte uns "...." wohl mitteilen

-
Sorry das ich jetzt erst Antworte...hatte ein verlängertes Wochenende und konnte nicht früher wieder ins Netz.
*hmpf*
Wie kann man nur sowas übersehen...ich hab wahrscheinlich schon viel zu lange vor dem Code gesessen *g*
Genau das war das Problem! Ich bekomme die Antwort auf meine Anfrage jetzt praktisch sofort zurück. Ihr seid super!
Danke für die Hilfe, das Problem wurde erfolgreich gelöst!

MFG