Вы можете установить параметры сокетов SO_RCVTIMEO и SO_SNDTIMEO в boost asio? - PullRequest
5 голосов
/ 15 ноября 2008

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

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

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

Ответы [ 3 ]

3 голосов
/ 24 декабря 2008

Абсолютно! Boost ASIO позволяет получить доступ к собственным / базовым данным, которые в данном случае являются самой СОКЕТЕЙ. Итак, допустим, у вас есть:

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 голосов
/ 15 ноября 2008

Похоже, что он не встроен в 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 голосов
/ 22 сентября 2017

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

Для записи с тайм-аутом 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;
}

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

...