读和写信给同一个插座(TCP)采用选择
-
20-09-2019 - |
题
我们正在编写的客户和服务器做到(我认为是)非常简单的的网络通信。多个客户连接到服务器然后应该将数据发送回所有其他客户。
服务器只是坐在一个阻挡 select
环路等交通,并且当它来临时,将数据发送给其他客户。这似乎只是罚款。
问题是客户。在应对一读,它将有时候想到做一个写。
然而,我发现,如果我使用:
rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);
我的代码将块,直到有新的数据读取。但有时候(异步,从另外一个线程)我就会有新的数据,以编写关于该网络的通信线。因此,我希望我的选择周期性地醒,让我检查是否有数据编写,如:
if (select(....) != -1)
{
if (FD_SET(sockfd, &master_list))
// handle data or disconnect
else
// look for data to write and write() / send() those.
}
我试图设置的选择投票模式(或可笑的短超时):
// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);
但是,已经找到,那么客户永远不会得到任何进入的数据。
我还试图设置的座fd为不可阻挡,如:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
但是,这并不解决问题:
- 如果我的客户
select()
有没有struct timeval
, 读数据的工作,但它永远不会放开让我看看写的数据。 - 如果我的客户
select()
有一个timeval
得到它的投票,那么它永远不会信号,有进入的数据阅读,并且我应用程序冻结的思想,没有网络连接(尽管事实上,所有其他功能的电话已经成功地)
任何指针在所有有什么我可以做错了什么?它是不可能做到的读写在同一座(我不能相信那是真实)。
(编辑:正确的答案,和我记得的服务器上的而不是客户,是要有一个第二fd_set,并复制master_list之前,每个叫选择():
// declare and FD_ZERO read_fds:
// put sockfd in master_list
while (1)
{
read_fds = master_list;
select(...);
if (FD_ISSET(read_fds))
....
else
// sleep or otherwise don't hog cpu resources
}
)
解决方案
一切都看起来不错,除非你做if (FD_SET(sockfd, &master_list))
行。我有一个非常类似的代码结构,我用FD_ISSET
。你应该测试,如果列表设置,不要再设置它。除此之外,我看没有别的。
编辑。另外,我对超时以下内容:
timeval listening_timeout;
listening_timeout.tv_sec = timeout_in_seconds;
listening_timeout.tv_usec = 0;
也许有一个问题,如果你把它设置为0(因为你似乎是在做什么?)
EDIT2。我记得我遇到了一个奇怪的问题,当我不清除读取之后选择EXITED设置,我再次进入之前。我不得不做这样的事情:
FD_ZERO(&sockfd);
FD_SET(sockfd, &rd);
我正进入select
之前。我不记得为什么,但。
其他提示
我似乎记得一个有关创建和共享网络螺纹和被添加到描述符中的select调用主线程之间的读/写文件描述符特技。 此器FD已通过时,它有东西送主线程写入的一个字节。写入从选择呼叫唤醒网络线程和网络线程然后从共享缓冲器抓住数据并将其写入到网络然后返回在选择睡眠。
很抱歉,如果这是一个有点模糊,缺乏代码...我的记忆可能是不正确的..所以其他人可能有进一步引导你。
我看不出有什么问题与您的代码,因此它应该工作。如果你不能得到它的工作,一个方法来解决它是创建由你读线程和准备东西写在线程中使用的管道,而管道的读出端添加到您的select
集。然后,当其他线程已准备要写入的数据,它只是将管道上的东西,你的阅读线程被从select
唤醒,然后它可以做的写作。取决于如何经常有数据要读或写,这也可能是更有效的。
2线应该能够工作,同插座在一段时间,所以你的主线应该能够编写给客户,而其他一个睡在选择等待进入的数据。这当然假定,这两个线已经接到客户的名单。