假设我们接受了一个客户端文件描述符并带有accept()
client_socket = accept(_socket, (sockaddr *)&client_addr, &len)现在,我们在读写fd_set中设置这个文件描述符:
fd_set readfds;
fd_set writefds;
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
FD_SET(client_socket, &writefds);现在,我们使用select检查套接字是可读的还是可写的:
select(FD_SETSIZE, &readfs, &writefds, NULL, NULL)现在我们检查是否可以先读取并从其中读取所有字节。
if (FD_ISSET(client_socket, &readfds) {
read(client_socket, &buf, 4096);
}
//assume that buf is big enough and that read returns less than 4096在下一个循环中,我们像以前一样重置fd_sets。现在,select将允许我们将响应写入客户端:
if (FD_ISSET(client_socket, &readfds) {
write(client_socket, &buf, len(buf));
}直到现在,一切都很好,但现在奇怪的行为发生了。假设我们的客户端告诉我们保持连接活动,在这种情况下,我们将像以前一样设置fd_set:
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
FD_SET(client_socket, &writefds);
// reading not allowed当使用select时,它将允许我们再次写入,但它不允许从client_socket读取。但是,如果我们将写的设置更改为零,它将允许我们读取,尽管我们没有在readfds中更改任何内容。
//zero them
FD_ZERO(readfds);
FD_ZERO(writefds);
//set the client_socket
FD_SET(client_socket, &readfds);
//FD_SET(client_socket, &writefds); -> don't set the file-descriptors for write
// now reading is allowed有人能解释一下这是否是select的正确行为,或者如果这是我的错,也许在我没有展示的代码的其他部分(太复杂了)。对我来说,在设置两个集合(写作和阅读)时,select的行为似乎是随机的。我知道有一种方法可以通过保持一种状态来决定我们是要设置读文件描述符还是写文件描述符,但是我希望有一个更干净的解决方案。
发布于 2022-03-16 15:21:05
select()的目的是在程序有事情可做之前不返回。这样,您的程序就可以在select()中睡觉,直到I/O准备好为止,立即醒来执行I/O操作,然后尽快回到睡眠状态。
所以问题是,select()如何知道什么时候返回?答案是,通过以适当的方式调用FD_SET(),您必须告诉它什么应该导致它返回。
通常,当您的任何套接字上的数据准备就绪时,您都希望select()返回(这样您就可以读取新到达的数据),所以通常应该在所有套接字上调用FD_SET(mySock, &readFD)。
FD_SET(mySock, &writeFD)有点细微之处。它告诉select(),当套接字有可用的缓冲区空间将输出字节写入到.但是,在许多情况下,当套接字有可用的缓冲区空间时,不希望返回select(),这仅仅是因为您目前没有任何希望写入套接字的数据。在这种情况下,如果您总是调用FD_SET(mySocket, &writeFD),那么即使您没有任何要执行的任务,select()也会立即返回,这将导致您的程序为了没有好的目的而消耗大量的CPU周期。
因此,您唯一应该调用FD_SET(mySocket, &writeFD)的时间是知道您想尽快将一些数据写入该套接字。
在您的程序中,可能发生的情况是,FD_SET(mySocket, &writeFD)导致select()立即返回(因为mySocket当前有可用的缓冲区空间可写入),然后程序(错误地)假设由于select()返回,套接字已准备好供阅读,结果却发现它不是。在您注释掉FD_SET(mySocket, &writeFD)、OTOH、select()的情况下,直到套接字准备好--可读--阅读时,才会返回,这样您就可以在调用FD_ISSET(mySocket, &readFD)时得到预期的行为。
https://stackoverflow.com/questions/71499436
复制相似问题