SO_RCVTIME和SO_RCVTIMEO不影响Boost.Asio的操作 [英] SO_RCVTIME and SO_RCVTIMEO not affecting Boost.Asio operations
问题描述
下面是我的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$c$c>是作为完成处理程序,以异步操作,启动函数会返回一个的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 $ C返回$ C>或
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 toEAGAIN
orEWOULDBLOCK
[...] Timeouts only have effect for system calls that perform socket I/O (e.g.,read()
,recvmsg()
, [...]; timeouts have no effect forselect()
,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()$c$c>大致对应于文件描述符的非阻塞状态模式。这种模式会影响系统的I / O调用。例如,如果一个调用
socket.native_non_blocking(真)
,那么的recv(socket.native_handle(),...)
可能会失败,错误号
设置为EAGAIN
或EWOULDBLOCK
。每当一个异步操作的插座上启动,Boost.Asio的将使该模式。 - <$c$c>non_blocking()$c$c>模式影响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 invokessocket.native_non_blocking(true)
, thenrecv(socket.native_handle(), ...)
may fail witherrno
set toEAGAIN
orEWOULDBLOCK
. 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 totrue
, Boost.Asio will set the underlying file descriptor to be non-blocking and synchronous Boost.Asio socket operations can fail withboost::asio::error::would_block
(or the equivalent system error). When set tofalse
, 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 ifEAGAIN
orEWOULDBLOCK
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 perSO_RCVTIMEO
. However, Boost.Asio will then immediately block polling on the file descriptor to be readable, which is not affected bySO_RCVTIMEO
. The final result is the caller blocked insocket.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 ignoreSO_RCVTIMEO
, immediately return withEAGAIN
orEWOULDBLOCK
, causingsocket.receive()
to fail withboost::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屋!