¿Puedes configurar las opciones de socket SO_RCVTIMEO y SO_SNDTIMEO en boost asio?

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

  •  08-07-2019
  •  | 
  •  

Pregunta

¿puede configurar las opciones de socket SO_RCVTIMEO y SO_SNDTIMEO en boost asio?

Si es así, ¿cómo?

Nota Sé que puede usar temporizadores en su lugar, pero me gustaría saber sobre estas opciones de socket en particular.

¿Fue útil?

Solución

¡Absolutamente! Boost ASIO le permite acceder a los datos nativos / subyacentes, que en este caso es el SOCKET en sí. Entonces, digamos que tienes:

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

Y supongamos que ya ha llamado a open o bind o alguna función miembro que realmente hace que my_socket sea utilizable. Luego, para obtener el valor SOCKET subyacente, llame al:

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

¡Entonces ahí lo tienes! El ASIO de Boost le permite hacer muchas cosas más rápido de lo que de otro modo podría hacer, pero hay muchas cosas que aún necesita para las llamadas normales de la biblioteca de sockets. Este es uno de ellos.

Otros consejos

No parece estar integrado en Boost.Asio (a partir del Boost SVN actual), pero, si está dispuesto a escribir sus propias clases para simular el boost :: asio :: detail :: socket_option , siempre puede seguir los ejemplos en boost / asio / socket_base.hpp y hacer lo siguiente:

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, no estoy sugiriendo que inyecte la clase timeval en el espacio de nombres boost :: asio :: detail :: socket_option , pero no puedo pensar de una buena para usar en este momento. :-P)

Editar: mi implementación de muestra de socket_option :: timeval , basada en 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_;
};

Una solución fácil a este problema sería utilizar las funciones de lectura y escritura nativas.

Para escribir con tiempo de espera de 1 segundo:

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 leer con tiempo de espera de 1 segundo:

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

Esto funcionó bien para mí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top