SO_RCVTIME和SO_RCVTIMEO不影响Boost.Asio的操作 [英] SO_RCVTIME and SO_RCVTIMEO not affecting Boost.Asio operations

查看:1018
本文介绍了SO_RCVTIME和SO_RCVTIMEO不影响Boost.Asio的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我的code

boost::asio::io_service io;
boost::asio::ip::tcp::acceptor::reuse_address option(true);
boost::asio::ip::tcp::acceptor accept(io);
boost::asio::ip::tcp::resolver resolver(io);
boost::asio::ip::tcp::resolver::query query("0.0.0.0", "8080");
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
accept.open(endpoint.protocol());
accept.set_option(option);
accept.bind(endpoint);
accept.listen(30);

boost::asio::ip::tcp::socket ps(io);

accept.accept(ps);

struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
//setsockopt(ps.native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
setsockopt(ps.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
char buf[1024];
ps.async_receive(boost::asio::buffer(buf, 1024), boost::bind(fun));
io.run();

当我使用Telnet连接,但不发送数据时,它不会从断开的Telnet timeout.Will需要做的,使setsockopt的踢?
谢谢!

When I use Telnet to connect, but not sending data, it does not disconnect from a Telnet timeout.Will need to do to make setsockopt kick in? Thanks!

我已经修改SO_RCVTIMEO到SO_SNDTIMEO。仍无法在规定时间超时

I have modified SO_RCVTIMEO to SO_SNDTIMEO. Still unable to timeout in the specified time

推荐答案

使用 SO_RCVTIMEO SO_SNDTIMEO 套接字选项与Boost.Asio的很少会产生所需的行为。请考虑使用以下两种模式:

Using SO_RCVTIMEO and SO_SNDTIMEO socket options with Boost.Asio will rarely produce the desired behavior. Consider using either of the following two patterns:

我们可以通过使用Boost.Asio的定时器和 async_wait()与操作 async_receive()缀以超时异步读操作操作。这种方法演示了Boost.Asio的<一个href=\"http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/examples/cpp03_examples.html#boost_asio.examples.cpp03_examples.timeouts\">timeout范例,类似于:

One can compose an asynchronous read operation with timeout by using a Boost.Asio timer and an async_wait() operation with a async_receive() operation. This approach is demonstrated in the Boost.Asio timeout examples, something similar to:

// Start a timeout for the read.
boost::asio::deadline_timer timer(io_service);
timer.expires_from_now(boost::posix_time::seconds(1));
timer.async_wait(
  [&socket, &timer](const boost::system::error_code& error)
  {
    // On error, such as cancellation, return early.
    if (error) return;

    // Timer has expired, but the read operation's completion handler
    // may have already ran, setting expiration to be in the future.
    if (timer.expires_at() > boost::asio::deadline_timer::traits_type::now())
    {
      return;
    } 

    // The read operation's completion handler has not ran.
    boost::system::error_code ignored_ec;
    socket.close(ignored_ec);
  });

// Start the read operation.
socket.async_receive(buffer,
  [&socket, &timer](const boost::system::error_code& error,
    std::size_t bytes_transferred)
  {
    // Update timeout state to indicate the handler has ran.  This
    // will cancel any pending timeouts.
    timer.expires_at(boost::posix_time::pos_infin);

    // On error, such as cancellation, return early.
    if (error) return;

    // At this point, the read was successful and buffer is populated.
    // However, if the timeout occurred and its completion handler ran first,
    // then the socket is closed (!socket.is_open()).
  });

注意,它是可能的异步操作能在相同的迭代完成,使得既完成处理程序准备与成功运行。因此,之所以都完成处理需要更新和检查状态。请参见回答关于如何管理状态的更多详细信息。

Be aware that it is possible for both asynchronous operations to complete in the same iteration, making both completion handlers ready to run with success. Hence, the reason why both completion handlers need to update and check state. See this answer for more details on how to manage state.

Boost.Asio的公司提供了<一个href=\"http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/overview/cpp2011/futures.html\">support对于C ++ 11期货的。当<一个href=\"http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/reference/use_future.html\"><$c$c>boost::asio::use_future是作为完成处理程序,以异步操作,启动函数会返回一个的std ::未来一旦操作完成后,将得到满足。由于的std ::未来支持定时等待,人们可以利用它为超时的操作。请注意,由于该调用线程将被阻塞,等待未来,至少另一个线程必须处理 io_service对象允许 async_receive() 操作进步和履行承诺:

Boost.Asio's provides support for C++11 futures. When boost::asio::use_future is provided as the completion handler to an asynchronous operation, the initiating function will return a std::future that will be fulfilled once the operation completes. As std::future supports timed waits, one can leverage it for timing out an operation. Do note that as the calling thread will be blocked waiting for the future, at least one other thread must be processing the io_service to allow the async_receive() operation to progress and fulfill the promise:

// Use an asynchronous operation so that it can be cancelled on timeout.
std::future<std::size_t> read_result = socket.async_receive(
   buffer, boost::asio::use_future);

// If timeout occurs, then cancel the read operation.
if (read_result.wait_for(std::chrono::seconds(1)) == 
    std::future_status::timeout)
{
  socket.cancel();
}
// Otherwise, the operation completed (with success or error).
else
{
  // If the operation failed, then read_result.get() will throw a
  // boost::system::system_error.
  auto bytes_transferred = read_result.get();
  // process buffer
}


为什么 SO_RCVTIMEO 将不起作用

系统行为

SO_RCVTIMEO 文档指出,只有选择影响系统调用执行套接字I / O,如阅读() recvmsg()。它不影响事件解复用器,如选择()调查(),只有看文件描述符确定何时I /可以不受阻塞O发生。此外,当确实发生超时时,I / O调用失败返回 1 并设置错误号 EAGAIN EWOULDBLOCK


Why SO_RCVTIMEO Will Not Work

System Behavior

The SO_RCVTIMEO documentation notes that the option only affects system calls that perform socket I/O, such as read() and recvmsg(). It does not affect event demultiplexers, such as select() and poll(), that only watch the file descriptors to determine when I/O can occur without blocking. Furthermore, when a timeout does occur, the I/O call fails returning -1 and sets errno to EAGAIN or EWOULDBLOCK.

指定接收或发送超时,直到报告错误。 [...]如果没有数据已转移,达到超时则 1 时,errno设置为 EAGAIN EWOULDBLOCK [...]超时只对系统调用执行套接字I / O(例如,读)效应( recvmsg() [...];超时有)没有效果选择(调查() epoll_wait(),等等。

Specify the receiving or sending timeouts until reporting an error. [...] if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK [...] Timeouts only have effect for system calls that perform socket I/O (e.g., read(), recvmsg(), [...]; timeouts have no effect for select(), poll(), epoll_wait(), and so on.

在底层文件描述符设置为非阻塞,系统调用执行套接字I / O将与 EAGAIN 立即返回或 EWOULDBLOCK 如果资源没有立即可用。对于非阻塞套接字, SO_RCVTIMEO 不会有任何影响,因为调用将成功或失败立即返回。因此,对于 SO_RCVTIMEO 来影响系统的I / O调用,插座必须阻止。

When the underlying file descriptor is set to non-blocking, system calls performing socket I/O will return immediately with EAGAIN or EWOULDBLOCK if resources are not immediately available. For a non-blocking socket, SO_RCVTIMEO will not have any affect, as the call will return immediately with success or failure. Thus, for SO_RCVTIMEO to affect system I/O calls, the socket must be blocking.

首先,在Boost.Asio的异步I / O操作将使用事件多路分离器,如选择()调查()。因此, SO_RCVTIMEO 不会影响异步操作。

First, asynchronous I/O operations in Boost.Asio will use an event demultiplexer, such as select() or poll(). Hence, SO_RCVTIMEO will not affect asynchronous operations.

接下来,Boost.Asio的的插座有两个非阻塞模式(两者默认为false)的概念:

Next, Boost.Asio's sockets have the concept of two non-blocking modes (both of which default to false):


  • <$c$c>native_non_blocking()大致对应于文件描述符的非阻塞状态模式。这种模式会影响系统的I / O调用。例如,如果一个调用 socket.native_non_blocking(真),那么的recv(socket.native_handle(),...)可能会失败,错误号设置为 EAGAIN EWOULDBLOCK 。每当一个异步操作的插座上启动,Boost.Asio的将使该模式。

  • <$c$c>non_blocking()模式影响Boost.Asio的的同步套接字操作。当设置为真正,Boost.Asio的将设置底层的文件描述符是非阻塞和同步Boost.Asio的插座操作可能会失败,升压: :ASIO ::错误:: WOULD_BLOCK (或等值系统错误)。如果当设置为,Boost.Asio的将阻塞,即使底层的文件描述符是非阻塞,通过轮询文件描述符并重新尝试系统I / O操作 EAGAIN EWOULDBLOCK 被返回。

  • native_non_blocking() mode that roughly corresponds to the file descriptor's non-blocking state. This mode affects system I/O calls. For example, if one invokes socket.native_non_blocking(true), then recv(socket.native_handle(), ...) may fail with errno set to EAGAIN or EWOULDBLOCK. Anytime an asynchronous operation is initiated on a socket, Boost.Asio will enable this mode.
  • non_blocking() mode that affects Boost.Asio's synchronous socket operations. When set to true, Boost.Asio will set the underlying file descriptor to be non-blocking and synchronous Boost.Asio socket operations can fail with boost::asio::error::would_block (or the equivalent system error). When set to false, Boost.Asio will block, even if the underlying file descriptor is non-blocking, by polling the file descriptor and re-attempting system I/O operations if EAGAIN or EWOULDBLOCK are returned.

从生产所需的行为non_blocking() prevents SO_RCVTIMEO 的行为。假设 socket.receive()是调用和数据既不是可用的也不接收:

The behavior of non_blocking() prevents SO_RCVTIMEO from producing desired behavior. Assuming socket.receive() is invoked and data is neither available nor received:


  • 如果 non_blocking()是假的,系统的I / O调用将每 SO_RCVTIMEO 超时。然而,Boost.Asio的将随即阻断文件描述符轮询是可读的,它不会受 SO_RCVTIMEO 。最终的结果是挡在 socket.receive(),直到数据已被接收或失效,如对端关闭连接调用者​​。

  • 如果 non_blocking()为真,那么底层的文件描述符也无阻塞。因此,系统I / O调用会忽略 SO_RCVTIMEO ,立即返回与 EAGAIN EWOULDBLOCK ,引起 socket.receive()失败,的boost ::支持ASIO ::错误:: WOULD_BLOCK

  • If non_blocking() is false, the system I/O call will timeout per SO_RCVTIMEO. However, Boost.Asio will then immediately block polling on the file descriptor to be readable, which is not affected by SO_RCVTIMEO. The final result is the caller blocked in socket.receive() until either data has been received or failure, such as the remote peer closing the connection.
  • If non_blocking() is true, then the underlying file descriptor is also non-blocking. Hence, the system I/O call will ignore SO_RCVTIMEO, immediately return with EAGAIN or EWOULDBLOCK, causing socket.receive() to fail with boost::asio::error::would_block.

在理想情况下,为 SO_RCVTIMEO 与Boost.Asio的运作,需要 native_non_blocking()设置为false,以便 SO_RCVTIMEO 可采取的影响,但也有 non_blocking()设置为true,在描述符prevent投票。然而,Boost.Asio的不<一个href=\"http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/reference/basic_stream_socket/native_non_blocking/overload2.html\">support这:

Ideally, for SO_RCVTIMEO to function with Boost.Asio, one needs native_non_blocking() set to false so that SO_RCVTIMEO can take affect, but also have non_blocking() set to true to prevent polling on the descriptor. However, Boost.Asio does not support this:

插座:: native_non_blocking(布尔模式)

如果该模式为,但的当前值non_blocking()真正,此函数失败与的boost ::支持ASIO ::错误:: invalid_argument ,作为组合没有意义。

If the mode is false, but the current value of non_blocking() is true, this function fails with boost::asio::error::invalid_argument, as the combination does not make sense.

这篇关于SO_RCVTIME和SO_RCVTIMEO不影响Boost.Asio的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆