você pode definir SO_RCVTIMEO e SO_SNDTIMEO opções de socket em impulso asio?

StackOverflow https://stackoverflow.com/questions/292997

  •  08-07-2019
  •  | 
  •  

Pergunta

Você pode definir SO_RCVTIMEO e SO_SNDTIMEO opções de socket no impulso asio?

Se sim, como?

Nota Eu sei que você pode usar temporizadores em vez disso, mas eu gostaria de saber sobre essas opções de socket em particular.

Foi útil?

Solução

Com certeza! Impulso ASIO permite que você acesse os / dados subjacentes nativos, que neste caso é o próprio SOCKET. Então, vamos dizer que você tem:

boost::asio::ip::tcp::socket my_socket;

E digamos que você já chamou open ou bind ou alguma função membro que realmente faz my_socket utilizável. Então, para obter o valor SOCKET subjacente, chamada:

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>);
}

Então, você tem isso! ASIO do impulso permite fazer muitas coisas mais rapidamente do que de outra forma poderia ser capaz de, mas há um monte de coisas que você ainda precisa as chamadas normais de biblioteca de soquete para. Isto acontece por ser um deles.

Outras dicas

Ele não parece ser construído em Boost.Asio (a partir de SVN impulso atual), mas, se você estiver disposto a escrever suas próprias classes para simular os boost::asio::detail::socket_option, você sempre pode seguir os exemplos boost/asio/socket_base.hpp e faça o seguinte:

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;

(Obviamente, eu não estou sugerindo que você injetar a classe timeval no namespace boost::asio::detail::socket_option, mas eu não consigo pensar em uma boa para uso no momento. :-P)

Edit: Minha implementação amostra de socket_option::timeval, com base em 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_;
};

Uma solução alternativa fácil para este problema seria a de utilizar as funções de leitura e gravação nativas.

Para escrever com tempo limite 1seg:

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);
}

Para ler com tempo limite 1seg:

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;
}

Esta funcionou bem para mim.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top