Unix/C 问题在这里。
我有多个套接字,我正在尝试轮询周期性数据。我不想 select 无限期地等待,所以我有一个超时,并且我正在循环中运行。我发现一旦套接字准备好读取,它就始终准备好读取。例如,当没有从任何套接字读取数据时,我无法让 select 进入睡眠状态。
for (i = 0; i < n_connections; i++) {
FD_SET( sockfd[i], &master );
if (sockfd[i] > fdmax)
fdmax = sockfd[i];
}
for(;;) {
int nready = 0;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
read_fds = master;
if ( (nready = select(fdmax+1, &read_fds, NULL, NULL, NULL)) == -1 ) {
fprintf( stderr, "Select Error\n" );
return FAILURE;
}
printf( "Number of ready descriptors: %d\n", nready );
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
if (( nbytes = recv(i, buf, sizeof(buf), 0)) <= 0 ) {
if (nbytes == 0) {
//connection closed
printf("Socket %d hung up\n", i );
}
else {
fprintf( stderr, "Recv Error %d\n", nbytes);
}
}
else {
printf( "Data Received on %d: %s\n", i, buf );
}
}
} // end file descriptor loop
似乎在我第一次读取之后,1 秒超时不再适用,并且套接字始终“准备好读取”,即使有 0 字节可用。我怎样才能让 select 进入睡眠状态,直到数据进入(一秒钟,或者将最后一个参数切换为 NULL,无限期地等待套接字上的数据进入?)
输出:
Number of Ready Descriptors: 2
Data Received on 4: GreetingsChap
Data Received on 5: HiMatengsChap
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
注意:为了清晰起见,更新了代码 根据 @yvesBraumes 的建议进行了更新 - 仍然不起作用。
如果检测到连接关闭,请从 fd 集中删除该套接字,否则
select
将报告它们(Socket 4 hung up
).. select 不是边缘触发的,如果不处理该事件,它是又要举报了。
事实上,如果recv返回0(而不是-1,errno=EWOULDBLOCK),则套接字被关闭。您也应该对其调用
close()
,并将其从 select()
调用中取出。否则会一直处于WAIT1状态,每次都会释放select()
。
您错误地使用了 FD_ISSET。您需要将套接字 ID 传递给“fd”参数,而不是索引:
if (FD_ISSET(i, &read_fds))...
需要
if (FD_ISSET(sockfd[i], &read_fds))...
同样适用于
recv
。