Sie können SO_RCVTIMEO und SO_SNDTIMEO Socket-Optionen im Boost Asio eingestellt?
-
08-07-2019 - |
Frage
können Sie einstellen, SO_RCVTIMEO und SO_SNDTIMEO Socket-Optionen im Boost Asio?
Wenn ja, wie?
Hinweis: Ich weiß, Sie Timer stattdessen verwenden können, aber ich möchte über diese Socket-Optionen insbesondere kennen.
Lösung
Auf jeden Fall! Steigern Sie ASIO können Sie die nativen / zugrundeliegenden Daten zugreifen können, die in diesem Fall ist die Buchse 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 einige Memberfunktion aufgerufen haben, die tatsächlich my_socket
nutzbar macht. Dann den darunter liegenden STECK Wert zu erhalten, rufen Sie:
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 haben Sie es! Boost-ASIO können Sie schnell viele Dinge mehr tun, als Sie sonst in der Lage sein könnte, aber es gibt eine Menge Dinge, die Sie immer noch die normalen Socket-Bibliothek fordert müssen. Dies geschieht, einer von ihnen sein.
Andere Tipps
Es scheint nicht in Boost.Asio gebaut werden (als aktueller Boost-SVN), aber, wenn Sie bereit sind, Ihre eigenen Klassen zu schreiben, um die boost::asio::detail::socket_option
diejenigen zu simulieren, können Sie immer die Beispiele in boost/asio/socket_base.hpp
folgen und Gehen Sie folgendermaßen vor:
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 behaupte nicht, dass 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)
Edit: 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_;
};
Eine einfache Behelfslösung für dieses Problem wäre das native Lese zu verwenden und Funktionen schreiben.
mit 1 S Timeout Schreiben:
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);
}
mit 1 S Timeout 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;
}
Das funktionierte gut für mich.