首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么选择-行为不同时,试图读取和写入套接字?

为什么选择-行为不同时,试图读取和写入套接字?
EN

Stack Overflow用户
提问于 2022-03-16 15:04:34
回答 1查看 48关注 0票数 0

假设我们接受了一个客户端文件描述符并带有accept()

代码语言:javascript
复制
client_socket = accept(_socket, (sockaddr *)&client_addr, &len)

现在,我们在读写fd_set中设置这个文件描述符:

代码语言:javascript
复制
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检查套接字是可读的还是可写的:

代码语言:javascript
复制
select(FD_SETSIZE, &readfs, &writefds, NULL, NULL)

现在我们检查是否可以先读取并从其中读取所有字节。

代码语言:javascript
复制
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将允许我们将响应写入客户端:

代码语言:javascript
复制
if (FD_ISSET(client_socket, &readfds) {
    write(client_socket, &buf, len(buf));
}

直到现在,一切都很好,但现在奇怪的行为发生了。假设我们的客户端告诉我们保持连接活动,在这种情况下,我们将像以前一样设置fd_set:

代码语言:javascript
复制
//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中更改任何内容。

代码语言:javascript
复制
//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的行为似乎是随机的。我知道有一种方法可以通过保持一种状态来决定我们是要设置读文件描述符还是写文件描述符,但是我希望有一个更干净的解决方案。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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)时得到预期的行为。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71499436

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档