Linux:是否有超时的套接字读取或recv?

osg*_*sgx 92 c sockets linux tcp

如何尝试从超时的套接字读取数据?我知道,select,pselect,poll,有一个超时字段,但使用它们会禁用tcp reno stack中的"tcp fast-path".

我唯一的想法是在循环中使用recv(fd,...,MSG_DONTWAIT)

Rob*_*nes 175

您可以使用setsockopt函数在接收操作上设置超时:

SO_RCVTIMEO

设置超时值,该值指定输入函数在完成之前等待的最长时间.它接受一个timeval结构,其中包含秒数和微秒数,指定等待输入操作完成的时间限制.如果接收操作在没有接收到额外数据的情况下被阻塞了这么长时间,则如果没有收到数据,它将返回部分计数或errno设置为[EAGAIN]或[EWOULDBLOCK].此选项的默认值为零,表示接收操作不应超时.此选项采用timeval结构.请注意,并非所有实现都允许设置此选项.

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
Run Code Online (Sandbox Code Playgroud)

据说在Windows上这应该在致电之前完成bind.我已经通过实验验证了它可以bind在Linux和OS X 之前或之后完成.

  • 是的,它会的.非常感谢 (5认同)
  • 这个答案救了我的屁股。我一直在实施那个令人费解的“选择”废话,但没有成功。这立即生效,非常简单。 (4认同)
  • 即使在绑定操作之后,这也适用于 Windows。在 Windows 10 上试过 (2认同)
  • @user463035818 [这个答案](/sf/answers/3484348591/)声称它不应该。 (2认同)

Abd*_*hri 20

这是一个简单的代码,使用C中的poll来为你的recv函数添加时间:

struct pollfd fd;
int ret;

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
    case -1:
        // Error
        break;
    case 0:
        // Timeout 
        break;
    default:
        recv(mySocket,buf,sizeof(buf), 0); // get your data
        break;
}
Run Code Online (Sandbox Code Playgroud)

  • 查看 <https://man7.org/linux/man-pages/man2/recv.2.html> 和 <https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf -winsock-recv>,“recv”应返回最多“sizeof(buf)”字节的任何可用数据量。所以这个解决方案应该没问题。 (3认同)