Frage

Gibt es eine Möglichkeit, eine anstehende Operation (ohne Trenn) abzubrechen oder einen Timeout für die Boost-Bibliotheksfunktionen eingestellt?

d. Ich möchte auf blockierenden Socket im Boost Asio ein Timeout setzen?

socket.read_some (boost :: asio :: Puffer (pData, maxSize), Fehler _);

Beispiel: Ich mag einige aus der Steckdose lesen, aber ich möchte einen Fehler werfen, wenn 10 Sekunden vergangen

.
War es hilfreich?

Lösung

Unter Linux / BSD das Timeout auf I / O-Operationen auf Buchsen direkt vom Betriebssystem unterstützt wird. Die Option kann über setsocktopt() aktiviert werden. Ich weiß nicht, ob boost::asio ein Verfahren bereit, es für die Einstellung oder legt die Buchse scriptor Sie direkt, damit sie eingestellt - letzteres der Fall ist nicht wirklich tragbar.

Für eine der Vollständigkeit halber hier die Beschreibung des Mannes Seite:

  

SO_RCVTIMEO und SO_SNDTIMEO

          Specify the receiving or sending  timeouts  until  reporting  an
          error.  The argument is a struct timeval.  If an input or output
          function blocks for this period of time, and data has been  sent
          or  received,  the  return  value  of  that function will be the
          amount of data transferred; if no data has been transferred  and
          the  timeout has been reached then -1 is returned with errno set
          to EAGAIN or EWOULDBLOCK just as if the socket was specified  to
          be  non-blocking.   If  the timeout is set to zero (the default)
          then the operation  will  never  timeout.   Timeouts  only  have
          effect  for system calls that perform socket I/O (e.g., read(2),
          recvmsg(2), send(2), sendmsg(2)); timeouts have  no  effect  for
          select(2), poll(2), epoll_wait(2), etc.

Andere Tipps

Wenn diese Frage gestellt wurde, ich denke, ASIO hat kein Beispiel dafür, wie zu erreichen, was die OP benötigt, dh eine Sperroperation wie eine blockierenden Socket Operation Timeout. Nun gibt es Beispiele, die Ihnen genau zu zeigen, wie dies zu tun. das Beispiel scheint lang, aber das ist, weil es gut kommentiert wird. Es zeigt, wie die ioservice in einem ‚One Shot‘ Art-Modus verwenden.

ich glaube, das Beispiel eine große Lösung ist. Die anderen Lösungen hier brechen Portabilität und nutzen nicht von ioservice. wenn Portabilität ist nicht wichtig und die ioservice scheint, wie zu viel Overhead --THEN-- sollten Sie nicht ASIO werden. Egal was passiert, werden Sie eine ioservice erstellt haben (fast alle ASIO-Funktionalität hängt davon ab, auch Synchronbuchsen) so, sie nutzen.

Timeout eine Blockierung Asio tcp Betrieb

Timeout eine Blockierung Asio udp Betrieb

Die ASIO Dokumentation wurde aktualisiert, so dass es für neue Beispiele, wie Besuche ASIO einige der ‚gotchas‘ zu überwinden, nutzen zu haben.

Sie könnten eine async_read tun und auch einen Timer für die gewünschte Zeit aus eingestellt. Dann, wenn der Timer Feuer, rufen Sie auf Ihrem Socket-Objekt löschen. Andernfalls, wenn beim Lesen geschieht, können Sie Ihre Timer abzubrechen. Dies erfordert, dass Sie ein io_service Objekt natürlich verwenden.

edit: Gefunden ein Code-Snippet für Sie, das dies tut

http://lists.boost.org/Archives/boost/ 2007/04 / 120339.php

hatte ich die gleiche Frage, und nach einigen Recherchen, die einfachste und sauberste Lösung, die ich tun konnte war die zugrunde liegende nativen Socket zu bekommen, und machen Sie einen wählen, bis es Daten zu lesen war. Wählen Sie einen Timeout-Parameter nehmen. Natürlich beginnt mit der nativen Steckdose arbeitet gegen den Punkt zu gehen Asio in erster Linie der Verwendung, aber auch hier scheint dies der sauberste Weg zu sein. Soweit ich könnte sagen, ist Asio nicht bietet eine Möglichkeit, dies für eine synchrone Verwendung leicht zu tun. Code:

        // socket here is:  boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr

        // Set up a timed select call, so we can handle timeout cases.

        fd_set fileDescriptorSet;
        struct timeval timeStruct;

        // set the timeout to 30 seconds
        timeStruct.tv_sec = 30;
        timeStruct.tv_usec = 0;
        FD_ZERO(&fileDescriptorSet);

        // We'll need to get the underlying native socket for this select call, in order
        // to add a simple timeout on the read:

        int nativeSocket = a_socket_ptr->native();

        FD_SET(nativeSocket,&fileDescriptorSet);

        select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);

        if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout

                std::string sMsg("TIMEOUT on read client data. Client IP: ");

                sMsg.append(a_socket_ptr->remote_endpoint().address().to_string());

                throw MyException(sMsg);
        }

        // now we know there's something to read, so read
        boost::system::error_code error;
        size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error);

        ...

Vielleicht wird dies für Ihre Situation nützlich sein.

TL; DR

socket.set_option(boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO>{ 200 });

FULL ANTWORT Diese Frage immer wieder aufgefordert, immer und immer wieder für viele Jahre. Antworten, die ich bisher gesehen sind ziemlich schlecht. Ich werde diese Informationen hinzufügen, hier in einer der ersten Vorkommen dieser Frage.

Jeder versucht, ASIO zu verwenden, um ihren Netzwerk-Code zu vereinfachen wäre vollkommen glücklich, wenn der Autor nur einen optionalen Parameter Timeout auf alle sync und async io Funktionen hinzufügen würde. Leider (in meiner bescheidenen Meinung nach, nur aus ideologischen Gründen, immerhin AS in ASIO aus einem Grunde ist) geschehen, ist dies unwahrscheinlich.

Das sind also die Möglichkeiten, diese arme Katze so weit vorhanden, um die Haut, keiner von ihnen besonders appetitlich. Sagen wir, wir brauchen 200 ms Timeout.

1) Gut (sehr schlecht) alter Socket-API:

const int timeout = 200;
::setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof timeout);//SO_SNDTIMEO for send ops

Bitte beachten Sie, diese Besonderheiten: - const int für Timeout - unter Windows die erforderlichen Typ ist eigentlich DWORD, aber der aktuelle Satz von Compilern zum Glück hat es die gleiche, so const int funktioniert sowohl in Win und Posix Welt. - (const char *) für Wert. Auf const char * Windows erforderlich ist, erfordert Posix const void *, wird in C ++ const char * konvertieren Leere const * still, während das Gegenteil ist nicht wahr.

Vorteile: Arbeiten und wahrscheinlich werden immer funktionieren, wie der Socket-API alt und stabil ist. Einfach genug. Schnell. Nachteile: technisch könnten entsprechende Header-Dateien (andere auf Win und sogar verschiedene UNIX-Derivaten) benötigen für setsockopt und Makros, aber aktuelle Implementierung von ASIO verpestet globalen Namensraum mit ihnen sowieso. Erfordert eine Variable für Timeout. Nicht typsicher. Unter Windows erfordert, dass der Sockel in überlappten Modus zu arbeiten (die aktuelle ASIO Implementierung glücklicherweise verwendet, aber es ist immer noch eine Implementierung Detail). UGLY!

2) Benutzerdefinierte ASIO Socket-Option:

typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option; //somewhere in your headers to be used everywhere you need it
//...
socket.set_option(rcv_timeout_option{ 200 });

Vorteile: Einfach genug. Schnell. Schön (mit typedef). Nachteile: Abhängig von ASIO Implementierungsdetail, das ändern könnte (aber OTOH alles wird schließlich ändern, und so detailliert ist weniger wahrscheinlich, dann öffentliche APIs unterliegt Standardisierung ändern). Aber falls dies der Fall ist, werden Sie haben entweder eine Klasse schreiben gemäß https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/SettableSocketOption.html (was natürlich ein wichtiges PITA dank offensichtlich Overengineering von dieser Teil der ASIO) oder besser noch auf 1 zurück.

3) Verwendung C ++ async / future-Einrichtungen.

#include <future>
#include <chrono>
//...
auto status = std::async(std::launch::async, [&] (){ /*your stream ops*/ })
    .wait_for(std::chrono::milliseconds{ 200 });
switch (status)
    {
    case std::future_status::deferred:
    //... should never happen with std::launch::async
        break;
    case std::future_status::ready:
    //...
        break;
    case std::future_status::timeout:
    //...
        break;
    }

Vorteile: Standard. Nachteile: beginnen immer einen neuen Thread (in der Praxis), die relativ langsam ist (vielleicht für die Kunden gut genug sein, aber für Server zu DoS-Schwachstelle führen, wie Fäden und Steckdosen „teuer“ Ressourcen). Versuchen Sie nicht, std :: Start verwenden :: statt std :: verschoben starten :: async neuen Thread Start zu vermeiden, da wait_for immer future_status zurückkehren :: latente ohne versuchen, um den Code auszuführen.

4) Das Verfahren vorgeschriebene ASIO -. Nur Asynchron-Operationen verwenden (was auf die Frage nicht wirklich die Antwort)

Vorteile: gut genug für Server auch wenn große Skalierbarkeit für kurze Transaktionen ist nicht erforderlich. Nachteile: ziemlich wortreich (so werde ich nicht einmal Beispiele sind - siehe ASIO Beispiele). Erfordert eine sehr sorgfältige Lebensdauer Verwaltung aller Objekte sowohl durch asynchrone Operationen und dessen Abschluss-Handler verwendet, die in der Praxis alle Klassen erfordert enthalten, und die Verwendung solcher Daten in asynchronen Operationen von enable_shared_from_this abgeleitet wird, die alle diese Klassen auf Heap zugewiesen erfordert, was bedeutet, ( zumindest für kurze Operationen), die Skalierbarkeit verjüngen sich nach etwa 16 Fäden wie jeder Halde alloc startet / dealloc wird eine Speicherbarriere verwenden.

Im Anschluss an dem, was grepsedawk erwähnt. Es gibt ein paar Beispiele, die zeigen, wie lange asynchrone Operationen nach einer Zeit der Laufzeit zu kündigen, unter dem Timeouts innerhalb Asio doco. Asio Beispiele Erhöhung . Async TCP-Client half mir am meisten.

Happy Asyncing:)

Auch Jahre nach der ursprünglichen Frage, gibt es noch keine befriedigende Antwort.

manuell mit select ist keine gute Option

  1. Dateideskriptors Zahl muss kleiner sein als 1024
  2. FD spuriously als fertig gemeldet werden können, aufgrund falscher Prüfsumme.

Anruf io_service.run_one() ist auch eine schlechte Idee, weil es andere Asynchron-Optionen sein kann, die eine io_service immer run() muss. Und Dokument Schub über TCP-Client blockiert ist schwer zu begreifen.

So, hier ist meine Lösung. Die Schlüsselidee ist folgende:

{
    Semaphore r_sem;
    boost::system::error_code r_ec;
    boost::asio::async_read(s,buffer,
                            [this, &r_ec, &r_sem](const boost::system::error_code& ec_, size_t) {
                                r_ec=ec_;
                                r_sem.notify();
                            });
    if(!r_sem.wait_for(std::chrono::seconds(3))) // wait for 3 seconds
    {
        s.cancel();
        r_sem.wait();
        throw boost::system::system_error(boost::asio::error::try_again);
    }
    else if(r_ec)
        throw boost::system::system_error(r_ec);
}

Hier Semaphore ist nur ein Mutex und ein condition_variable.
wait_for implementiert von http://en.cppreference.com/w/cpp/ Gewinde / condition_variable / wait_for

Voll Code ist unter https://github.com/scinart /cpplib/blob/master/include/asio.hpp
Beispiele sind in https://github.com/scinart/ cpplib / Blob / Master / test / test_asio.cpp
Besseres Beispiel unter https://github.com/scinart/cpplib/blob /master/test/test_SyncBoostIO.cpp

Sie können die synchronen Aufrufe in Futures wickeln und warten, bis es mit einem Timeout (wait_timeout) in Anspruch nehmen.

http: // www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.futures

Sicher nicht one size fits all, aber funktioniert gut für z.B. Umgehen langsam Timeouts verbinden.

Auf * nichts, dann würden Sie verwenden Alarm (), damit Ihr Socket-Aufruf mit EINTR versagen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top