2016-11-22 5 views
-1

Ich habe versucht, dies viel zu suchen. Ich bin neu in network+tcp-sockets Programmierung.boost :: asio :: in TCP-Client-App lesen dauert lange Zeit, wenn Konnektivität verloren geht

Ich verwende TCP sockets, um Daten über das Netzwerk zu kommunizieren. Ich habe ein host app & ein client app sowohl in geschrieben C++ & Verwendung boost::asio an beiden Enden Daten zu kommunizieren.

In der client app verwende ich boost::asio::read, um einige Daten aus einer socket in meiner C++ - Client-Anwendung zu lesen. Die Hostanwendung wird auf einem anderen Computer ausgeführt.

Folgendes ist der Code, wo ich einige Daten lesen & versuchen, festzustellen, ob es Fehler gibt.

boost::system::error_code error_code; 
std::size_t data_received = boost::asio::read(socket, boost::asio::buffer(&data_to_read, sizeof(data_to_read)), error_code); 
if (error_code == boost::asio::error::eof) { 
    //ends here if the host app closes the socket 
    //log error & return 
} 

if (data_received <= 0) { 
    //log error & return 
} 

Ich erhalte eine boost::asio::error::eof wenn Host App die Socket geschlossen und es funktioniert meine UI aktualisieren zu zeigen, dass ich die Verbindung verloren haben.

Aber hier ist das Problem: Wenn die network/wifi in der Host-App geht dann dauert boost::asio::read eine lange Zeit, um zurückzukehren. So etwas wie 2 Minuten. Dann bekomme ich nach langer Zeit einen boost::asio::error::eof Fehler. Seltsam ! Ich kann mir diese Latenz nicht leisten, da ich für den Benutzer schnell aktualisieren muss, dass Daten nicht aus der host app abgerufen werden konnten.

Warum kehrt asio nicht schnell zurück, wenn das Netzwerk ausgeschaltet oder die Verbindung unterbrochen ist? Gibt es eine andere Möglichkeit, dies zu erkennen oder damit umzugehen?

PS: Beachten Sie, dass boost::asio::read ein blockierenden Aufruf ist aber nicht gesperrt mein UI-Thread, wenn es Zeit braucht, zurückzukehren, weil ich dies in einem worker thread tue.

+0

Was ist lokale IP? Denn wenn das Loopback ist, hat es nichts mit WLAN zu tun. Loopback "immer" funktioniert – sehe

+0

ja @sehe. Aber, das lokale IP-Ding war unnötige zusätzliche Information. Daher habe ich es aus meiner Frage entfernt –

+0

Da Sie den UI-Thread nicht blockieren, warum nicht den UI-Thread die Benutzeroberfläche aktualisieren und den Benutzer wissen lassen, dass Daten nicht vom Host abgerufen werden konnten? Es ist Ihre Entscheidung, was zu tun ist, während dieses blockierende Lesen blockiert.Wenn Sie diesen Thread nicht blockieren möchten, bis das Lesen abgeschlossen ist oder endgültig fehlschlägt, führen Sie keinen blockierenden Leseanruf durch. Sie bekommen, wonach Sie gefragt haben - wenn Sie es nicht mögen, fragen Sie nach etwas anderem. –

Antwort

2

TCP ist so konzipiert, dass es selbst bei scheinbar katastrophalen Problemen "zuverlässig" ist. Dies geschieht mit einer Reihe von Timern und erneuten Übertragungen, wenn das andere Ende einer Verbindung nicht antwortet. Wie oft und wie lange die Neuübertragungen stattfinden, hängt vom Betriebssystem ab. Es kann Minuten oder sogar Stunden dauern, bevor eine Verbindung gemeldet wird.

Interne Sockets haben eine Gruppe von Optionen, um Keep Alive-Einstellungen zu steuern, die Sie auf den Socket setzen können (wenn boost :: asio diese verfügbar macht). Eine schnelle Google-Suche nach "tcp keepalive" brachte eine Reihe von Beispielen.

Eine andere Möglichkeit ist es, einen eigenen Zeitmechanismus zu implementieren, in dem Sie ständig Pakete & Antworten über die TCP-Verbindung senden & definieren Sie sich, was das richtige Timing sein sollte.

+0

Ich suchte nach 'tcp :: no_delay'. Gefunden einige Links wie eine [hier] (http://stackoverflow.com/questions/5706641/asio-iptcpiostream-and-tcp-nodelay). 'boost :: asio' scheint auch dafür Unterstützung zu haben. Aber es scheint, als könnte ich es verwenden, wenn ich 'boost :: asio :: ip :: tcp :: iostream' verwende, um meinen Puffer zu lesen. In meinem Code, wenn ich versuche, 'tcp :: no_delay (true)' zu setzen, sollte ich es dann vor jedem 'boost :: asio :: read'-Aufruf setzen? –

+1

@SegmentationFault 'tcp :: no_delay' löst ein anderes Problem. TCP keepalive ist ein Ping, der Fehler schneller meldet. Wenn Sie das Protokoll kontrollieren, besteht der beste Ansatz darin, Ihren eigenen Verbindungstestmechanismus zu implementieren, wie @evan beschreibt. – janm

+1

Ich sollte auch erwähnen, dass die Keep-Alive-Einstellungen plattformabhängig sind, ebenso wie ihre Konfigurierbarkeit. – evan