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


105

如何尝试在超时的情况下从套接字读取数据?我知道,选择,pselect,轮询具有超时字段,但是使用它们会禁用tcp reno堆栈中的“ tcp快速路径”。

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


还有一个使用线程的选项:),但仍然需要线程信号
osgx 2010年

Answers:


189

您可以使用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);

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


1
这个答案救了我。我被困于实施那种令人费解的“选择”废话,但没有成功。这立即生效,非常简单。
MiloDC '17

现在这就是为什么Windows上的超时无法正常工作的原因,因为我正在使用Linux的代码。谢谢。如果Windows没有使用,struct timeval tv;那是否意味着select()也无法正常工作?我试图将我的select()代码移植到Windows,它只是立即超时,似乎忽略了我在timeval设置的值。
kuchi

1
我将超时值设置为5秒。为什么不管是否有输入数据,每个读取周期总是要花5秒钟?

即使在绑定操作之后,这也适用于Windows。在Windows 10上尝试过
cahit beyaz '18

1
@ user463035818 此答案认为不应该。
Tomeamis

22

这是一些简单的代码,可以在C中recv使用超时功能poll

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;
}

这将无法完全按预期工作。poll将等待接收至少一个字节或超时,而在调用该recv函数时将等待sizeof(buf)字节,如果尚未达到此计数(但这次没有超时),将导致它再次阻塞。
LoPiTaL

0

//对WINDOWS进行绑定操作后也可以使用

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

-1

安装的处理程序SIGALRM,然后在常规阻止之前使用alarm()或。如果警报响起,将会返回错误,其设置为。ualarm()recv()recv()errnoEINTR


8
警报(和信号)是执行此任务的错误方法。如果我想使用tcp快速路径,那么我需要最小的延迟。信号很慢。
osgx

2
@osgx仅在超时的情况下才会发出信号。
David Schwartz

-4

LINUX

struct timeval tv;
tv.tv_sec = 30;        // 30 Secs Timeout
tv.tv_usec = 0;        // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));

视窗

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

注意:您已将此设置放在bind()函数调用之前以正确运行


4
几年前已经回答了这个问题。您的解决方案带来什么新价值?
Maciej Jureczko

您已将此设置放在bind()函数调用之前以正确运行,这在ans中未提及
vivek
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.