2010-12-29 4 views
20

Beim Lesen anderer Stack Overflow-Einträge und der Dokumentation boost::asio habe ich bestätigt, dass es keine synchronen ASIO-Lese-/Schreibaufrufe gibt, die auch ein benutzerfreundliches Timeout als Parameter für den Anruf bereitstellen.C++ Boost ASIO: Wie man mit einem Timeout liest/schreibt?

Ich bin mitten in der Umwandlung einer alten Schule Linux-Socket-Anwendung mit Select (2) Anrufe, Timeouts verwendet, und ich muss mehr oder weniger das gleiche tun.

Was ist der beste Weg, dies in boost::asio zu tun? Wenn man sich die Asio-Dokumentation anschaut, gibt es viele verwirrende Beispiele für verschiedene Dinge, die mit Timern zu tun haben, aber ich bin ziemlich verwirrt.

Ich würde gerne ein einfach zu lesendes Beispiel dafür sehen: Lesen von einem Sockel, aber warten Sie für ein Maximum von X Sekunden nach dem die Funktion entweder mit nichts zurückkehrt, oder mit allem zurückkommt, was es konnte aus dem Socket zu lesen, bevor das Timeout abgelaufen ist.

+3

Können Sie bitte erläutern, was an diesem Beispiel verwirrend ist: http://think-async.com/Asio/asio-1.4.7/src/examples/timeouts/blocking_tcp_client.cpp - Die wesentliche Logik ist, dass Sie 2 asynchrone Tasks absetzen, einen einen Lese-/Schreibzugriff und den anderen eine Zeitüberschreitung, wenn der Lese-/Schreibzugriff zuerst beendet wird, wenn der Deadline-Timer beendet wird, wenn der Deadline-Timer die Logik zurückgibt ist immer noch herausragend - von da an geht es mit Ihrer Timeout-Logik weiter. sehr, sehr einfach. –

+2

Es gibt einen Eckfall, der in Hf-Netzwerk auftreten kann, das mit der Warteschlange der Rückrufe verbunden ist. Die Zeitüberschreitung cb wird in die Warteschlange gestellt, dann wird das Lesen/Schreiben in die Warteschlange gestellt. Sie treffen die Zeitüberschreitung cb und beginnen mit der Ausführung der Zeitüberwachungslogik, wenn in Wirklichkeit das Lesen/Schreiben abgeschlossen ist. Eine mögliche Lösung, die ich gesehen habe, ist etwas Ähnliches wie die Doppelschecksperre - kurz eine sekundäre Zeitüberschreitung durchführen, wenn die erste Zeitüberschreitung eintritt. aber dann hat dies das gleiche Problem, wenn das Lesen/Schreiben in die Warteschlange gestellt wird, nachdem das 2. Timeout ist Warteschlange ... –

+2

Denken Sie daran, ein Timeout ist eine harte Bedingung, Sie sagen, wenn ich etwas nicht in einer bestimmten Menge von bekommen Zeit, ich werde etwas Bestimmtes tun - das schließt die Tatsache ein, dass das Lesen/Schreiben bereits stattgefunden hat und auf dem Weg zu Ihnen ist, das ändert nichts an der Tatsache, dass Sie es noch nicht erhalten haben. –

Antwort

6

Dies wurde auf den Asio-Mailinglisten aufgezeigt, es gibt eine ticket Anforderung der Funktion. Zusammenfassend wird vorgeschlagen, asynchrone Methoden zu verwenden, wenn Timeouts und Löschbarkeit gewünscht sind.


Wenn Sie nicht auf asynchrone Methoden umwandeln kann, können Sie versuchen, die SO_RCVTIMEO und SO_SNDTIMEO Socket-Optionen. Sie können mit setsockopt eingestellt werden, der Deskriptor kann mit der boost::asio::ip::tcp::socket::native Methode erhalten werden. Die man 7 socket Manpage sagt

SO_RCVTIMEO und SO_SNDTIMEO die Empfangs Geben oder das Versenden von Timeouts, bis ein Fehler meldet. Das Argument ist eine Struktur timeval. Wenn ein Eingang oder Ausgang Funktion für diesen Zeitraum von Zeit blockiert, und Daten gesendet oder empfangen wurden, ist der Rückgabewert dieser Funktion die Menge der übertragenen Daten; Wenn keine Daten übertragen wurden und das Timeout erreicht wurde, wird -1 mit zurückgegeben, wobei errno auf EAGAIN oder EWOULDBLOCK gesetzt wird, als ob der Socket auf festgelegt wurde. Wenn das Zeitlimit auf Null gesetzt ist (Standardeinstellung), wird die Operation niemals ablaufen. Timeouts haben nur den Effekt für Systemaufrufe, die Socket-E/A durchführen (z. B. read (2), recvmsg (2), send (2), sendmsg (2)); Timeouts haben keine Auswirkungen für select (2), Umfrage (2), epoll_wait (2) usw.

+1

Haben Sie die Antwort von CH auf die Anfrage gelesen? ASIO repliziert die Betriebssystemfunktionalität in C++. Wenn Sie eine Art Time-out-Funktionalität benötigen, können Sie sie gerne mit den ASIO-Bit-n-Pieces implementieren. –

5

ich einige asio docs verwendet, um dieses zu produzieren:

class TimeoutAdjust 
{ 
public: 
    TimeoutAdjust(unsigned int dwTimeout) : m_dwTimeout(dwTimeout) {}; 

    template<class Protocol> 
    int level(const Protocol& p) const {return SOL_SOCKET;} 

    template<class Protocol> 
    int name(const Protocol& p) const {return SO_SNDTIMEO;} 

    template<class Protocol> 
    const void* data(const Protocol& p) const {return &m_dwTimeout;} 

    template<class Protocol> 
    size_t size(const Protocol& p) const {return sizeof(m_dwTimeout);} 
private: 
    unsigned int m_dwTimeout; 
}; 

Verbrauch:

TimeoutAdjust adjust(5000); 
sSocket.set_option(adjust); 

Ich debuggte es, und es scheint zu tun, was es soll.

+1

Was ich hier gelesen habe ist, dass 'SO_SNDTIMEO' ein' timeval' nimmt, anstatt ein 'unsigned int'. http://linux.die.net/man/7/socket – updogliu

+0

Ah, die MS-Dokumente verwenden ein DWORD für SO_SNDTIMEO. Sieht so aus, als ob es sich bei Timeval um ein Paar Long-Ints handelt. MS docs: http://msdn.microsoft.com/en-ca/library/windows/desktop/ms740532(v=vs.85).aspx – ArtHare

+2

Nach der Verwendung des obigen Codes bekomme ich eine Ausnahme Ausnahme: set_option: Ungültig argument.Wenn Sie einen Referenzcode haben, teilen Sie bitte das gleiche. – asim