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

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

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

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


person Brian R. Bondy    schedule 15.11.2008    source источник


Ответы (3)


Абсолютно! 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 позволяет делать многие вещи быстрее, чем вы могли бы в противном случае, но есть много вещей, для которых вам все еще нужны обычные вызовы библиотеки сокетов. Это один из них.

person Brian    schedule 23.12.2008
comment
все функции send / recv самого нижнего уровня имеют for (;;) циклы вокруг вызовов, которые явно перехватывают EAGAIN. Это фактически делает параметры SO_ {SND, RCV} TIMEO бесполезными, если вы не отбросите 95% функций отправки / получения в Boost. Таким образом, спорно, что они позволяют вам устанавливать параметры, потому что единственный способ воспользоваться этим - не использовать остальную часть библиотеки ... - person Tom; 03.07.2009

Похоже, что он не встроен в 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_;
};
person Chris Jester-Young    schedule 15.11.2008
comment
Я не мог просто сделать: typedef boost :: asio :: detail :: socket_option :: integer ‹SOL_SOCKET, SO_SNDTIMEO› send_timeout; И то же самое для тайм-аута recv? Зачем вам еще нужна структура timeval? - person Brian R. Bondy; 20.11.2008
comment
Хахаха, вы увидите в первой версии моего ответа, я тоже так подумал. Однако прочтите opengroup.org/onlinepubs/009695399/functions/setsockopt.html, и вы увидите, что значения тайм-аута используют timeval, а не int. - person Chris Jester-Young; 20.11.2008
comment
Осторожно: в Win32 SO_SNDTIMEO берет DWORD, а не timeval. - person rustyx; 10.03.2021

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

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

У меня это сработало.

person Andrea Bondavalli    schedule 22.09.2017
comment
Почему? Что не так с чтением / записью asio? - person rustyx; 10.03.2021