2008-11-15 11 views

Respuesta

3

¡Absolutamente! Boost ASIO le permite acceder a los datos nativos/subyacentes, que en este caso es el SOCKET. Por lo tanto, digamos que usted tiene:

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

Y digamos que ya ha llamado open o bind o alguna función miembro que realmente hace my_socket utilizable. Entonces, para obtener el valor TOMA subyacente, llame a:

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>); 
} 

Así que ahí lo tienen! ASIO de Boost le permite hacer muchas cosas más rápidamente de lo que de otra manera podría, pero hay muchas cosas que aún necesita para las llamadas normales de la biblioteca de sockets. Este pasa a ser uno de ellos.

+2

todas menos las funciones de enviar/recv de nivel más bajo tienen bucles (;;) alrededor de las llamadas que atrapan explícitamente EAGAIN. Esto hace que las opciones SO_ {SND, RCV} TIMEO sean inútiles a menos que deseche el 95% de las funciones de envío/recepción en Boost. Por lo tanto, es discutible que le permitan establecer las opciones, porque la única forma de aprovecharlo es no usar el resto de la biblioteca ... – Tom

+0

Excelente punto. Acabo de golpear esto ahora. Sucks. –

3

No parece estar integrado en Boost.Asio (a partir del actual SVN de Boost), pero, si está dispuesto a escribir sus propias clases para simular las boost::asio::detail::socket_option, siempre puede seguir los ejemplos en boost/asio/socket_base.hpp y hacer lo siguiente:

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; 

(Obviamente, no estoy sugiriendo que se inyecte la clase timeval en el boost::asio::detail::socket_option espacio de nombres, pero no puedo pensar en una buena para usar en el momento :-P).

Editar: Mi ejemplo de implementación de socket_option::timeval, basado en 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

¿No podría simplemente hacer: typedef boost :: asio :: detail :: socket_option :: integer send_timeout; ¿Y lo mismo para el tiempo de espera de recv? ¿Por qué necesita la estructura timeval también? –

+0

Jajaja, verás en la primera versión de mi respuesta, eso es lo que pensé también. Sin embargo, lea http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html y verá que los valores de tiempo de espera usan timeval, no int. –

0

Una solución fácil a este problema sería utilizar las funciones nativas de lectura y escritura.

para escribir con tiempo de espera de 1 segundo:

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); 
} 

para leer con tiempo de espera de 1 segundo:

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; 
} 

Esto funcionó bien para mí.

Cuestiones relacionadas