2008-11-15 10 views

Odpowiedz

3

Absolutnie! Zwiększenie ASIO pozwala uzyskać dostęp do danych natywnych/bazowych, które w tym przypadku są samym SOCKET. Więc powiedzmy, że masz:

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

I powiedzmy, już nazywany open lub bind lub jakąś funkcję członka, który rzeczywiście sprawia my_socket użytkową. Następnie, aby uzyskać podstawową wartość SOCKET, zadzwoń pod numer:

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

Więc już to masz! System ASIO Boost umożliwia szybsze wykonywanie wielu czynności, niż jest to możliwe, ale wiele rzeczy nadal wymaga normalnych wywołań biblioteki gniazd. Tak się składa, że ​​jest jednym z nich.

+2

wszystkie oprócz funkcji najniższego poziomu wysyłania/recv mają dla (;;) pętle wokół wywołań, które jawnie wychwytują EAGAIN. To skutecznie czyni opcje SO_ {SND, RCV} TIMEO bezużytecznymi, chyba że odrzucisz 95% funkcji wysyłania/odbierania w trybie Boost. W związku z tym jest to kwestia, która pozwala na ustawienie opcji, ponieważ jedynym sposobem, aby z niego skorzystać, jest niewykorzystywanie reszty biblioteki ... – Tom

+0

Doskonały punkt. Właśnie to uderzyłem. Do kitu. –

3

Wygląda na to, że nie jest wbudowany w funkcję Boost.Asio (od bieżącego SVN), ale jeśli chcesz napisać własne zajęcia, aby zasymulować wersje boost::asio::detail::socket_option, możesz zawsze postępować zgodnie z przykładami podanymi w boost/asio/socket_base.hpp i wykonaj następujące czynności:

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; 

(Oczywiście, ja nie sugeruję wstrzyknąć klasy timeval do nazw boost::asio::detail::socket_option, ale nie mogę myśleć o dobrym nich korzystać w chwili :-P).

Edytuj: Moja przykładowa implementacja socket_option::timeval, oparta na 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

Nie mogę po prostu zrobić: typedef doładowanie :: asio :: detail :: socket_option :: integer send_timeout; A to samo dotyczy czasu oczekiwania na recv? Dlaczego potrzebujesz również struktury timeval? –

+0

Hahaha, zobaczysz w pierwszej wersji mojej odpowiedzi, tak też myślałem. Jednak przeczytaj http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html, a zobaczysz, że wartości limitu czasu używają timeval, nie int. –

0

Łatwym obejściem tego problemu byłoby wykorzystanie natywnych funkcji odczytu i zapisu.

Do pisania z limitu czasu 1 s:

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

Do czytania z limitu czasu 1 s:

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

To działało w porządku dla mnie.

Powiązane problemy