我试图理解Linux上的select()系统调用。为此,我编写了一个小程序,它将打开服务器和客户端套接字。客户端套接字将在新创建的线程中创建。客户端将向服务器发送大约90byte的数据(只是一个测试字符串)。在从服务器套接字读取之前,我以60秒的超时执行select()。
我现在的问题是:select每次都会超时。我检查了我的选择调用是否正确(我在调用之前设置了FD_Set),确保设置了服务器fd,并且选择了足够大的超时时间,以使正常的调度不会干扰它。但是,由于某些原因,我无法选择正常工作。
我的代码如下(用于调试,无论select()返回什么,我都阅读):
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”)。任何帮助,将不胜感激!
您必须选择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结构。内核会更新那里的值,以反映未花费的剩余时间。