套接字超时:选择与setsockopt

问题描述

我使用超时在套接字上发送和接收数据。我发现超时可以通过将套接字设置为非阻塞模式并使用 select 或使用 setsockoptSO_SNDTIMEO/SO_RCVTIMEO 选项来实现。
这两种方法之间有什么区别,对于 Linux (Redhat) 和 Windows,是否有任何理由更喜欢一种实现而不是另一种实现?

解决方法

这两种方法之间有什么区别,对于 Linux (Redhat) 和 Windows,是否有任何理由更喜欢一种实现而不是另一种实现?

对于 Linux,差异似乎相当小:

指定接收或发送超时直到报告错误。参数是一个结构体 timeval。如果输入或输出函数在这段时间内阻塞,并且已经发送或接收了数据,则该函数的返回值将是传输的数据量;如果没有数据传输并且超时,则返回 -1,并将 errno 设置为 EAGAIN 或 EWOULDBLOCK,或 EINPROGRESS(对于 connect(2))就好像套接字被指定为非阻塞.如果超时设置为零(默认值),则操作永远不会超时。超时仅对执行套接字 I/O 的系统调用有效(例如,read(2)、recvmsg(2)、send(2)、sendmsg(2));超时对 select(2)、poll(2)、epoll_wait(2) 等没有影响。

Source

但是,您没有方便的属性来同时多路复用多个连接,例如, select。 对于 Windows,差异更为严重:

阻塞发送调用的超时时间,以毫秒为单位。默认为 此选项为零,表示发送操作不会 超时。如果阻塞发送调用超时,连接处于 不确定状态,应关闭。如果创建了套接字 使用 WSASocket 函数,则 dwFlags 参数必须具有 WSA_FLAG_OVERLAPPED 属性设置为超时功能 适当地。否则超时永远不会生效。

Source

因此超时后,套接字将无法使用(这可能不是您想要的行为)。 唯一的原因是这种行为在两个 Berkely 套接字实现之间有所不同,我不建议使用 setsockopt(SO_SNDTIMEO/SO_RCVTIMEO),而是使用为此而创建的工具,例如select,或者更好的是像 boost::asio 这样的合适的网络套接字库。