Domanda

puoi impostare le opzioni socket SO_RCVTIMEO e SO_SNDTIMEO in boost asio?

Se sì, come?

Nota So che puoi usare i timer, ma mi piacerebbe conoscere queste opzioni socket in particolare.

È stato utile?

Soluzione

Assolutamente! Boost ASIO ti consente di accedere ai dati nativi / sottostanti, che in questo caso è lo SOCKET stesso. Quindi, supponiamo che tu abbia:

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

E supponiamo che tu abbia già chiamato open o bind o alcune funzioni membro che rendono effettivamente my_socket utilizzabili. Quindi, per ottenere il valore SOCKET sottostante, chiama:

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

Quindi il gioco è fatto! L'ASIO di Boost ti consente di fare molte cose più rapidamente di quanto potresti altrimenti fare, ma ci sono molte cose per cui hai ancora bisogno delle normali chiamate alla libreria dei socket. Questo sembra essere uno di questi.

Altri suggerimenti

Non sembra essere integrato in Boost.Asio (a partire dall'attuale Boost SVN), ma, se sei disposto a scrivere le tue classi per simulare il boost :: asio :: detail :: socket_option , puoi sempre seguire gli esempi in boost / asio / socket_base.hpp ed effettuare le seguenti operazioni:

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;

(Ovviamente, non sto suggerendo di inserire la classe timeval nello spazio dei nomi boost :: asio :: detail :: socket_option , ma non riesco a pensare di buono da usare al momento. :-P)

Modifica: la mia implementazione di esempio di socket_option :: timeval , basata su 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 soluzione semplice a questo problema sarebbe quella di utilizzare le funzioni native di lettura e scrittura.

Per scrivere con timeout di 1 secondo:

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

Per la lettura con timeout di 1 secondo:

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

Questo ha funzionato bene per me.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top