C++ t该选项仅影响执行套接字I/O的系统调用,例如read()和recvmsg()。它不会影响事件解复用器,例如select()和poll(),这些事件解复用器仅监视文件描述符以确定何时可以在不阻塞的情况下发生I/O。此外,当超时发生时,I/O调用无法返回-1,并将errno设置为EAGAIN或ewoodblock
指定接收或发送超时,直到报告错误。[…]如果未传输数据且已达到超时,则返回C++ t该选项仅影响执行套接字I/O的系统调用,例如read()和recvmsg()。它不会影响事件解复用器,例如select()和poll(),这些事件解复用器仅监视文件描述符以确定何时可以在不阻塞的情况下发生I/O。此外,当超时发生时,I/O调用无法返回-1,并将errno设置为EAGAIN或ewoodblock,c++,linux,boost,boost-asio,C++,Linux,Boost,Boost Asio,指定接收或发送超时,直到报告错误。[…]如果未传输数据且已达到超时,则返回-1,并将errno设置为EAGAIN或ewoodblock[…]超时仅对执行套接字I/O的系统调用有效(例如,read(),recvmsg(),[…];超时对select()无效)、poll()、epoll\u wait(),等等 当底层文件描述符设置为非阻塞时,执行套接字I/O的系统调用将立即返回EAGAIN或ewoodblock,如果资源不立即可用。对于非阻塞套接字,SO_RCVTIMEO将不会有任何影响,因为调用将
-1
,并将errno设置为EAGAIN
或ewoodblock
[…]超时仅对执行套接字I/O的系统调用有效(例如,read()
,recvmsg()
,[…];超时对select()无效)
、poll()
、epoll\u wait()
,等等
当底层文件描述符设置为非阻塞时,执行套接字I/O的系统调用将立即返回EAGAIN
或ewoodblock
,如果资源不立即可用。对于非阻塞套接字,SO_RCVTIMEO
将不会有任何影响,因为调用将立即返回并成功或失败失败。因此,要使SO\u RCVTIMEO
影响系统I/O调用,套接字必须阻塞
助推,助推行为
首先,Boost.Asio中的异步I/O操作将使用事件解复用器,例如select()
或poll()
。因此,SO\u RCVTIMEO
不会影响异步操作
接下来,Boost.Asio的套接字具有两种非阻塞模式的概念(都默认为false):
- 大致对应于文件描述符的非阻塞状态的模式。此模式影响系统I/O调用。例如,如果调用
,则调用socket.native\u non\u blocking(true)
如果将recv(socket.native\u handle(),…)
设置为errno
或EAGAIN
,则可能会失败。只要在套接字上启动异步操作,Boost.Asio就会启用此模式eWoldBlock
- 影响Boost.Asio的同步套接字操作的模式。当设置为
时,Boost.Asio会将基础文件描述符设置为非阻塞和同步Boost。Asio套接字操作可能会因true
(或等效的系统错误)而失败。当设置为Boost::Asio::error::will_block
时,Boost.Asio将通过轮询文件描述符并在返回false
或EAGAIN
时重新尝试系统I/O操作来阻止,即使底层文件描述符是非阻塞的ewoodblock
non\u blocking()
的行为会阻止SO\RCVTIMEO
产生所需的行为。假设调用了socket.receive()
,并且数据既不可用也不接收:
- 如果
为false,系统I/O调用将根据non_blocking()
超时。但是,Boost.Asio随后将立即阻止对文件描述符的轮询以使其可读,这不受SO\u RCVTIMEO
的影响。最终结果是在SO_RCVTIMEO
直到收到数据或出现故障,如远程对等方关闭连接套接字中阻止调用方。receive()
- 如果
为true,则底层文件描述符也是非阻塞的。因此,系统I/O调用将忽略non\u blocking()
,立即返回SO\u RCVTIMEO
或EAGAIN
,导致ewoodblock
因socket.receive()
而失败boost::asio::error::will\u block
SO\u RCVTIMEO
与Boost.Asio一起工作,需要将native\u non\u blocking()
设置为false,以便SO\u RCVTIMEO
能够生效,但也需要将non\u blocking()
设置为true,以防止对描述符进行轮询。但是,Boost.Asio没有:
socket::本机非阻塞(bool模式)
如果模式为false
,但non_blocking()
的当前值为true
,此函数将失败,并出现boost::asio::error::invalid_参数
,因为组合没有意义
谢谢你提醒我。但即使我不能使用SO_RCVTIMEO async_,也会收到规定的超时。@fneig请尝试编辑后的答案并让我知道:)我不能说我完全理解实现,但感觉它可以正常工作。它调用套接字上的recv,该套接字可能会返回超时。然后,不调用poll,只返回超时错误。至少在windows上,设置SO_RCVTIMEO确实有效(简单地说,没有设置非阻塞模式等),至少在boost 1.64中是有效的,并且只做您所期望的。不知道为什么目前在非Windows平台上没有。
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();
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
void myclose(boost::asio::ip::tcp::socket& ps) { ps.close(); }
int main()
{
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);
char buf[1024];
boost::asio::deadline_timer timer(io, boost::posix_time::seconds(1));
timer.async_wait(boost::bind(myclose, boost::ref(ps)));
ps.async_receive(boost::asio::buffer(buf, 1024),
[](const boost::system::error_code& error,
std::size_t bytes_transferred )
{
std::cout << bytes_transferred << std::endl;
});
io.run();
return 0;
}