我有一个通过套接字连接的发送器和接收器。 当发送方发送某些内容时,我想使用 poll() 上的计时器来了解接收方是否没有返回确认。 读了很多问题后(为什么没有输入,poll 却不断返回?、嵌入式 Linux poll() 不断返回、poll(2) 没有清空事件队列)我明白了 poll即使接收者没有发回任何内容,() 函数也可以返回 1,因为 read() 函数不会在套接字的文件描述符上阻塞。
但我想使用 poll() 的超时来知道套接字上是否没有任何内容到达。 如何让 poll() 函数仅在新数据到达套接字时才返回 1?
这是我的代码示例,以防万一我做错了什么:
while(1){
rv = poll(ufds, ufds[0].fd +1 , 1000);
if (rv == -1) {
perror("poll");
} else if (rv == 0) {
printf("Timeout occurred! No data after 1 seconds.\n");
} else {
if (ufds[0].revents & POLLIN) {
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1)
{
die("recvfrom()");
}
printf("ACK = %s \n", buf);
}
if (ufds[0].revents & POLLPRI) {
if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1)
{
die("recvfrom()");
}
}
}
}
TL;DR:此代码永远不会打印“发生超时!”因为socket的文件描述符总是准备好的。我可以改变这种行为吗?
可能在链接的帖子中得到了回答,但基本思想是
poll
、select
和其他机制不会告诉您套接字上何时有新数据。正如您正确提到的,它们仅告诉您何时read()
不会阻塞。
您可以将
EPOLLET
与 Linux 的 epoll(7)
界面(其他系统可能有其他等效项)一起使用来完成您想要的操作;但请记住,这不是便携式的。
正确且可接受的设计是完全消耗网络缓冲区,将部分消息保留在应用程序定义的缓冲区中(即而不是在套接字缓冲区中)并跟踪需要从网络读取多少额外数据。
问题是,如果您写入文件描述符,当前不会阻塞。在这种情况下 poll 返回正数。即此轮询从未超时,这就是为什么您从未看到超时发生消息的原因。要解决此问题,您需要将轮询调用更改为仅查找接收事件。您可以在这里阅读有关民意调查的信息:http://linux.die.net/man/2/poll。
看这里的代码,似乎对 poll 的调用不正确。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
而不是传递
ufds[0].fd + 1
,假设数组中只有一个结构体,poll 调用应该是:
rv = poll(ufds, 1, 1000);
正如上面的代码所示,它可能假设 ufds 数组有多个成员并读取无效的 pollfd 结构,导致无效返回。