2008-11-15 5 views

Antwort

3

Absolut! Boost ASIO ermöglicht Ihnen den Zugriff auf die nativen/zugrunde liegenden Daten, in diesem Fall die SOCKET selbst. Also, lassen Sie uns sagen, Sie haben:

boost::asio::ip::tcp::socket my_socket; 

Und lassen Sie uns sagen, dass Sie bereits open oder bind oder eine Member-Funktion aufgerufen haben, die tatsächlich my_socket nutzbar macht. Um dann den zugrunde liegenden SOCKET-Wert zu erhalten, rufen Sie an:

SOCKET native_sock = my_socket.native(); 
int result = SOCKET_ERROR; 

if (INVALID_SOCKET != native_sock) 
{ 
    result = setsockopt(native_sock, SOL_SOCKET, <the pertinent params you want to use>); 
} 

So, Sie haben es! Mit dem ASIO von Boost können Sie viele Dinge schneller erledigen, als Sie es sonst könnten, aber es gibt eine Menge Dinge, die Sie für normale Socket-Bibliotheksaufrufe benötigen. Dies ist einer von ihnen.

+2

alle außer den niedrigsten send/recv Funktionen haben für (;;) Schleifen um die Aufrufe, die explizit EAGAIN abfangen. Dies macht effektiv SO_ {SND, RCV} TIMEO Optionen nutzlos, wenn Sie 95% der Sende-/Empfangsfunktionen in Boost verwerfen. Daher ist es strittig, dass sie Ihnen erlauben, die Optionen zu setzen, weil der einzige Weg, um davon zu profitieren, ist, den Rest der Bibliothek nicht zu verwenden ... – Tom

+0

Ausgezeichneter Punkt. Ich habe das jetzt gerade getroffen. Saugt. –

3

Es scheint nicht in Boost.Asio (ab dem aktuellen Boost SVN) gebaut werden, aber wenn Sie bereit sind, Ihre eigenen Klassen zu schreiben, um die boost::asio::detail::socket_option zu simulieren, können Sie immer die Beispiele in boost/asio/socket_base.hpp folgen und wie folgt vorgehen:

typedef boost::asio::detail::socket_option::timeval<SOL_SOCKET, SO_SNDTIMEO> 
    send_timeout; 
typedef boost::asio::detail::socket_option::timeval<SOL_SOCKET, SO_RCVTIMEO> 
    receive_timeout; 

(Natürlich, ich bin nicht darauf hindeutet Sie die timeval Klasse in den boost::asio::detail::socket_option Namensraum injizieren, aber ich kann nicht glauben, von einem guten im Moment zu verwenden :-P.)

Bearbeiten: Meine Beispielimplementierung von socket_option::timeval, basierend auf socket_option::integer:

// Helper template for implementing timeval options. 
template <int Level, int Name> 
class timeval 
{ 
public: 
    // Default constructor. 
    timeval() 
    : value_(zero_timeval()) 
    { 
    } 

    // Construct with a specific option value. 
    explicit timeval(::timeval v) 
    : value_(v) 
    { 
    } 

    // Set the value of the timeval option. 
    timeval& operator=(::timeval v) 
    { 
    value_ = v; 
    return *this; 
    } 

    // Get the current value of the timeval option. 
    ::timeval value() const 
    { 
    return value_; 
    } 

    // Get the level of the socket option. 
    template <typename Protocol> 
    int level(const Protocol&) const 
    { 
    return Level; 
    } 

    // Get the name of the socket option. 
    template <typename Protocol> 
    int name(const Protocol&) const 
    { 
    return Name; 
    } 

    // Get the address of the timeval data. 
    template <typename Protocol> 
    ::timeval* data(const Protocol&) 
    { 
    return &value_; 
    } 

    // Get the address of the timeval data. 
    template <typename Protocol> 
    const ::timeval* data(const Protocol&) const 
    { 
    return &value_; 
    } 

    // Get the size of the timeval data. 
    template <typename Protocol> 
    std::size_t size(const Protocol&) const 
    { 
    return sizeof(value_); 
    } 

    // Set the size of the timeval data. 
    template <typename Protocol> 
    void resize(const Protocol&, std::size_t s) 
    { 
    if (s != sizeof(value_)) 
     throw std::length_error("timeval socket option resize"); 
    } 

private: 
    static ::timeval zero_timeval() 
    { 
    ::timeval result = {}; 
    return result; 
    } 

    ::timeval value_; 
}; 
+0

Konnte ich nicht einfach tun: typedef boost :: asio :: detail :: socket_option :: ganzzahl send_timeout; Und das gleiche für die Recv Timeout? Warum brauchst du auch die timeval Struktur? –

+0

Hahaha, du wirst in der ersten Version meiner Antwort sehen, das habe ich auch gedacht. Lesen Sie jedoch http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html und Sie werden sehen, dass die Zeitüberschreitungswerte timeval und nicht int verwenden. –

0

Eine einfache Lösung für dieses Problem wäre die Verwendung der systemeigenen Lese- und Schreibfunktionen.

Zum Schreiben mit 1sec Timeout:

struct timeval tv = { 1, 0 }; 
setsockopt(socket.native_handle(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); 
ssize_t nsent = ::write(socket->native_handle(), buff, size); 
if (nsent > 0) { 
    BOOST_LOG_TRIVIAL(debug) << "Sent " << nsent << " bytes to remote client " << ep; 
} else if (nsent == 0) { 
BOOST_LOG_TRIVIAL(info) << "Client " << ep << " closed connection"; 
} else if (errno != EAGAIN) { 
    BOOST_LOG_TRIVIAL(info) << "Client " << ep << " error: " <<  strerror(errno); 
} 

Für mit 1sec Timeout zu lesen:

struct timeval tv = { 1, 0 }; 
setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); 
ssize_t nread = ::read(socket.native_handle(), buff, audio_buff_size); 
if (nread > 0) { 
} else if (nread == 0) { 
    BOOST_LOG_TRIVIAL(info) << "Source " << source << " server " << host << " closed connection"; 
    break; 
} else if (errno != EAGAIN) { 
    BOOST_LOG_TRIVIAL(info) << "Source " << source << " server " << host << " error: " << strerror(errno); 
    break; 
} 

Dies funktionierte gut für mich.