你可以在 boost asio 中设置 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项吗?
如果有怎么办?
注意我知道你可以使用计时器,但我特别想知道这些套接字选项。
你可以在 boost asio 中设置 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项吗?
如果有怎么办?
注意我知道你可以使用计时器,但我特别想知道这些套接字选项。
绝对地!Boost ASIO 允许您访问本机/底层数据,在这种情况下是 SOCKET 本身。所以,假设你有:
boost::asio::ip::tcp::socket my_socket;
假设您已经调用了openorbind或一些实际上可以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 让您可以比其他方式更快地完成许多事情,但是您仍然需要正常的套接字库调用很多事情。这恰好是其中之一。
它似乎没有内置到 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_;
};
    解决此问题的一个简单方法是使用本机读写功能。
对于 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;
}
这对我来说很好。