2008-11-15 2 views
5

Можете ли вы установить параметры сокета SO_RCVTIMEO и SO_SNDTIMEO в boost asio?Можете ли вы установить параметры сокета SO_RCVTIMEO и SO_SNDTIMEO в boost asio?

Если да, то как?

Примечание. Я знаю, что вы можете использовать таймеры вместо этого, но я хотел бы узнать об этих параметрах сокета в частности.

ответ

3

Абсолютно! Boost ASIO позволяет получить доступ к исходным/базовым данным, что в данном случае является самой SOCKET. Итак, предположим, что у вас есть:

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

И скажем, вы уже назвали open или bind или какой-либо функции-члена, что на самом деле делает my_socket годный к употреблению. Затем, чтобы получить базовое значение SOCKET, позвоните по телефону:

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

Итак, у вас оно есть! ASIO от Boost позволяет вам делать много вещей быстрее, чем вы могли бы быть в состоянии, но есть много вещей, которые вам по-прежнему нужны для обычных вызовов сокетов. Это один из них.

3

Он не кажется встроенным в Boost.Asio (с текущего Boost SVN), но если вы хотите написать свои собственные классы для имитации boost::asio::detail::socket_option, вы всегда можете следовать примерам в boost/asio/socket_base.hpp и выполните следующие действия:

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; 

(Очевидно, я не предлагаю вам вводить timeval класс в boost::asio::detail::socket_option пространство имен, но я не могу думать о хорошем, чтобы использовать один в момент :-P.)

Редактировать: Моя примерная реализация socket_option::timeval, основанная на 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

Не могу я просто сделать: typedef boost :: asio :: detail :: socket_option :: integer send_timeout; И то же самое для тайм-аута recv? Зачем вам нужна структура timeval? – 2008-11-20 00:29:12

+0

Хахаха, вы увидите в первой версии моего ответа, вот что я подумал. Однако прочитайте http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html, и вы увидите, что значения таймаута используют timeval, а не int. – 2008-11-20 04:43:49

0

Простой подход к этой проблеме заключается в использовании собственных функций чтения и записи.

для записи с 1 сек таймаута:

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

Для чтения с 1 сек таймаута:

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

Это работало отлично для меня.