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 结构。那里的值由内核更新以反映未花费等待的剩余时间。
我正在尝试了解 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 结构。那里的值由内核更新以反映未花费等待的剩余时间。