Select return 0 但可以读取数据

Select return 0 but data can be read

我正在尝试了解 Linux 上的 select() 系统调用。为此,我编写了一个可以打开服务器和客户端套接字的小程序。客户端套接字将在新创建的线程中创建。客户端将向服务器发送大约 90 字节的数据(只是一个测试字符串)。在从服务器套接字读取之前,我执行了一个超时为 60 秒的 select()。

我现在的问题是:select每次都会超时。我检查了我的 select 调用是否正确(我在调用之前设置了 FD_Set),我确保服务器 fd 已设置并且我选择了足够大的超时以便正常调度不会干扰它。然而,出于某种原因,我无法让 select 正常工作。

我的代码如下(为了调试,我不管 select() returns 是什么):

struct timeval tv = {
    .tv_sec = 60,
    .tv_usec = 0,
};    
printf("[+] Creating server socket!\n");
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) 
{ 
    // set error and exit
} 
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) 
{ 
    // set error and exit
} 
if (bind(server_fd, (struct sockaddr *)&address_block, sizeof(address_block))<0) 
{ 
    // set error and exit
} 

//Create client thread here
pthread_create(&p2, NULL, client_function, NULL);

if (listen(server_fd, 3) < 0) 
{ 
    // set error and exit
} 

if ((new_socket = accept(server_fd, (struct sockaddr *)&address,  (socklen_t*)&addrlen))<0) 
{ 
    // set error and exit
} 

printf("\t[select] Non-Blocking Server fd is: %d\n", server_fd);

//create and set fds_non_blocking set    
FD_ZERO(&fds_non_blocking);
FD_SET(server_fd, &fds_non_blocking);


int select_return = select(server_fd + 1, &fds_non_blocking, NULL, NULL, &tv);

valread = read( new_socket , buffer, 1024); 

(注意:我知道我应该检查 select return 是否 >0 以及设置了哪个 FD)。函数 "client_function()" 做类似的事情,然后发送一个字符串。它会休眠 3 秒,并会一直在 select() 启动后发送数据。

执行本程序时,select会一直超时,select之后的读取总会收到客户端发送的数据

有人能看出我的错误吗?我已经将我的实现与其他实现进行了比较(最常见的错误是第一个 select 参数未设置为 "Server fd + 1")。任何帮助,将不胜感激!

你必须 select new_socket,而不是 server_fd:

FD_ZERO(&fds_non_blocking);
FD_SET(new_socket, &fds_non_blocking);

int select_return = select(new_socket + 1, &fds_non_blocking, NULL, NULL, &tv);

valread = read( new_socket , buffer, 1024); 

如果你想同时检查两个文件描述符,你可以使用

FD_ZERO(&fds_non_blocking);
FD_SET(new_socket, &fds_non_blocking);
FD_SET(server_fd, &fds_non_blocking);

int maxfd = (server_fd > new_socket)?server_fd+1:new_socket+1;   
int select_return = select(maxfd, &fds_non_blocking, NULL, NULL, &tv);

if (FD_ISSET(new_socket, &fds_non_blocking))
    valread = read( new_socket , buffer, 1024); 
else if (FD_ISSET(server_fd, &fds_non_blocking))
    ; // Accept a new client

否则,您将只会寻找要接受的新客户端连接,而不是寻找已接受套接字上的未决数据。

此外,您必须在每次调用 select() 后重置 timeval 结构。那里的值由内核更新以反映未花费等待的剩余时间。