2008-11-15 4 views

Répondre

3

Absolument! Boost ASIO vous permet d'accéder aux données natives/sous-jacentes, qui dans ce cas est la SOCKET elle-même. Alors, disons que vous avez:

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

Et disons que vous avez déjà appelé open ou bind ou une fonction membre qui fait réellement my_socket utilisable. Ensuite, pour obtenir la valeur SOCKET sous-jacente, appelez:

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

Alors là vous l'avez! ASIO de Boost vous permet de faire beaucoup de choses plus rapidement que ce que vous auriez pu faire autrement, mais il y a beaucoup de choses dont vous avez toujours besoin pour les appels normaux de la bibliothèque de socket. Cela arrive à être l'un d'entre eux.

+2

toutes sauf les fonctions d'envoi/recv de plus bas niveau ont pour (;;) boucles autour des appels qui interceptent explicitement EAGAIN. Cela rend les options SO_ {SND, RCV} TIMEO inutiles à moins que vous ne rejetiez 95% des fonctions d'envoi/de réception dans Boost. Ainsi, il est inutile qu'ils vous permettent de définir les options, car la seule façon d'en profiter est de ne pas utiliser le reste de la bibliothèque ... – Tom

+0

Excellent point. Je viens de frapper ça maintenant. Suce. –

3

Il ne semble pas être intégré dans Boost.Asio (comme Boost courant SVN), mais, si vous êtes prêt à écrire vos propres classes pour simuler les boost::asio::detail::socket_option ceux, vous pouvez toujours suivre les exemples boost/asio/socket_base.hpp et procédez comme suit:

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; 

(de toute évidence, je ne suggère pas que vous injectez la classe timeval dans l'espace de noms boost::asio::detail::socket_option, mais je ne peux pas penser à un bon à utiliser au moment :-P.)

Modifier: Mon exemple d'implémentation de socket_option::timeval, basé sur 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

Impossible de faire: typedef boost :: asio :: detail :: socket_option :: entier send_timeout; Et la même chose pour le timeout recv? Pourquoi avez-vous besoin de la structure timeval également? –

+0

Hahaha, vous verrez dans la première version de ma réponse, c'est ce que je pensais aussi. Cependant, lisez http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html et vous verrez que les valeurs de timeout utilisent timeval, pas int. –

0

Un moyen facile de contourner ce problème serait d'utiliser les fonctions natives de lecture et d'écriture.

Pour écrire avec délai 1sec:

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

Pour la lecture avec délai d'attente 1sec:

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

Cela a bien fonctionné pour moi.

Questions connexes