boost asioでSO_RCVTIMEOおよびSO_SNDTIMEOソケットオプションを設定できますか?
-
08-07-2019 - |
質問
boost asioでSO_RCVTIMEOおよびSO_SNDTIMEOソケットオプションを設定できますか?
もしそうなら?
注代わりにタイマーを使用できることは知っていますが、特にこれらのソケットオプションについて知りたいです。
解決
絶対に! 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>);
}
これでおしまいです! BoostのASIOを使用すると、他の方法よりも多くのことをすばやく実行できますが、通常のソケットライブラリの呼び出しに必要なものはまだたくさんあります。これはたまたまその1つです。
他のヒント
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;
(明らかに、 boost :: asio :: detail :: socket_option
名前空間に timeval
クラスを挿入することはお勧めしませんが、考えられません現時点で使用するのに適したものです。:-P)
編集: socket_option :: integer
:
socket_option :: timeval
のサンプル実装
// 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_;
};
この問題の簡単な回避策は、ネイティブの読み取りおよび書き込み機能を使用することです。
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;
}
これは私にとってはうまくいきました。