recv() nicht blockieren lassen



  • Ich arbeite mich momentan bei Windows-Sockets ein. Dabei soll nun auf eingehende Verbindungen gewartet werden und ein Client sendet etwas an den Server.

    Beim Empfangen schlägt die Funktion nun fehl mit dem Error-Code 10054:

    Connection reset by peer.
    

    Das Problem ist (glaube ich), dass mein recv() solange wartet bis die Gegenseite die Verbindung schließt, das will ich aber nicht.
    Nach dem ersten Empfangen soll der Server nämlich etwas zurücksenden, die Verbindung soll aufrecht erhalten bleiben.

    Wie schaffe ich es, dass mein recv() aufhört, wenn keine weiteren Daten gesendet werden?

    Mein Code:

    std::vector<char> buff;
    std::string mdata;
    buffer.resize(4096);
    
    int retval = 0;
    
    do {
    	ret = recv(_sock, &buff[0], buff.size(), 0);
    
    	if (ret == -1) {
    		return WSAGetLastError();
    	} 
    	else {
    		mdata.append(&buff[0], ret);
    	}
    } while (ret > 0);
    


  • Ich habe dafür immer

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx

    verwandt. Man könnte das natürlich auch threaden...



  • dkjztjkt schrieb:

    Wie schaffe ich es, dass mein recv() aufhört, wenn keine weiteren Daten gesendet werden?

    Naja, sorg einfach dafür, dass die andere Seite die Verbindung schließt, wenn nichts mehr gesendet werden soll... 😉



  • Es sollen ja nur zunächst keine weiteren Daten gesendet werden, da erst der Server antwortet und dann wieder neue Daten empfangen werden sollen.

    Werde mir select() mal anschauen, sieht aber arg komplex aus 😮





  • Du könntest einen nichtblockierenden Socket verwenden, oder aber ein Protokoll vereinbaren, etwa so, dass jeder Nachricht die Information über die Länge der Nachricht vorausgesendet wird. Der Empfänger weiß dann genau, wieviele Byte er lesen muss, bis die Nachricht komplett ist.



  • @dkjztjkt
    Sockets kennen keine "Block-Grenzen" oder ähnliches.

    D.h. der Client bzw. Server muss selbst wissen wann eine Nachricht "komplett" ist, also wann keine Daten mehr kommen.
    Eine Möglichkeit ist dazu den Socket einseitig zu schliessen - dann kann in dieser Richtung natürlich nichts mehr übertragen werden, und man braucht eine neue Connection für weitere Kommunikation.

    Die zweite Möglichkeit ist selbst eine Struktur für die Nachrichten zu definieren, mit der das Ende einer Nachricht erkennbar ist.
    Bei vielen Textbasierten Protokollen endet ein Request z.B. mit einem doppelten Zeilenumbruch.
    Oder man schickt einfach vorne die Länge des Blocks mit, dann muss die Gegenstelle nicht nach irgendwelchen Mustern suchen, sondern weiss immer genau wie viel Daten noch folgen.

    Die einzige andere Möglichkeit, die aber mMn. Quark ist, wäre ein bestimmtes Timeout festzulegen - also quasi "wenn 2 Sekunden nix mehr ankommt dann ist der Request vollständig".
    Das verlangsamt aber nicht nur sehr die Kommunikation, sondern ist auch überhaupt fehleranfällig, da TCP/IP schliesslich kein Timing garantiert. D.h. es kann passieren dass die 2 Sekunden Pause schon vor dem Ende der Nachricht kommen, trotz dem dass der Sender die Daten sogar "am Stück" weggeschickt hat. Dann glaubt der Empfänger der Request wäre vollständig, obwohl er es noch gar nicht ist. Auch nicht gut.



  • Belli schrieb:

    Du könntest einen nichtblockierenden Socket verwenden, oder aber ein Protokoll vereinbaren, etwa so, dass jeder Nachricht die Information über die Länge der Nachricht vorausgesendet wird.

    Wie, oder?
    Wie soll man das alleine mit non-blocking IO hinbekommen?
    Man muss ja trotzdem wissen wann die Nachricht komplett ist...



  • Das stimmt natürlich! Es würde Deinem als schlecht erachteten Ansatz mit dem Timeout in gewisser Weise ähneln.
    Aber es würde:

    dkjztjkt schrieb:

    Nach dem ersten Empfangen soll der Server nämlich etwas zurücksenden, die Verbindung soll aufrecht erhalten bleiben.

    Wie schaffe ich es, dass mein recv() aufhört, wenn keine weiteren Daten gesendet werden?

    ermöglichen.


  • Mod

    dkjztjkt schrieb:

    Wie schaffe ich es, dass mein recv() aufhört, wenn keine weiteren Daten gesendet werden?

    Das solltest Du doch an Deinem Datenprotokoll feststelen können...
    Wenn jeder Sendevorgang z.B. die Länge der folgenden Daten voransetzt, weißt Du wieviel für diesen Block noch zu lesen ist.
    Zugleich kannst Du sofort nach dem Empfang der Länge etwas zurück antworten...



  • @Belli
    Das sollte ohne asio/non-blocking IO auch gehen.
    recv() kommt ja auch bei blocking IO zurück sobald ein neues Stück Daten empfangen wurde. So lange der Server in der Wartezeit nichts anderes zu tun hat, reicht das.


Anmelden zum Antworten