c-用select()阻止,直到客户端获取或丢失



我需要知道客户端是否连接/断开并处理它。

这是我唯一的想法:

while(!serverStop)
{
    fd_set rfds, wfdsBefore, wfdsAfter;
    FD_ZERO(&rfds);
    FD_SET(serverFd, &rfds);
    FD_ZERO(&wfdsBefore);
    fillWithClientFds(&wfdsBefore); // clients only listen for messages
    wfdsAfter = wfdsBefore;
    while(1)
    {
        select(notimportant, &rfds, &wfdsAfter, NULL, NULL);
        if (FD_ISSET(serverFd, &rfds)) // new client appeared
            break;
        if (doSetsDiffer(&wfdsBefore, &wfdsAfter)) // some client disconnected (doesn't work)
            break;
    }
    // inform connected clients about disconnected ones
}

不仅会出现忙等待,而且这种方法甚至不起作用(尽管客户端关闭了套接字,但wfdsAfter不会改变)。

有什么办法吗?唯一的要求是不要使用多线程。

CCD_ 2是用CCD_ 3和CCD_。

您应该在连接后将每个客户端文件描述符放置在读取描述符(rfd)集中,并且当文件描述符随后返回为可读时,尝试从套接字读取。

首先,如果您的客户端真的没有发送任何内容(还没有断开连接),那么它的套接字将永远不会被标记为可读。这似乎可以解决你的问题,因为你说客户端实际上从未发送过任何东西:在客户端断开连接之前,它不会被标记为可读。

但是,即使客户端发送数据,只有当数据可用客户端已断开连接时,文件描述符才会被标记为可读。然后,您可以通过尝试读取套接字来轻松区分。返回值可以是读取的字节数(如果有数据),也可以是零(如果客户端已断开连接)。

(服务器通常会将O_NONBLOCK选项添加到套接字中,以确保当客户端有数据要发送时得到通知,但希望确保不会阻止等待来自客户端的数据。使用该选项,当客户端断开连接时,read仍然返回0。使用该选项,如果客户端仍在,但没有可用数据,则read调用将返回-1,errno设置为EAGAIN/EWOULDBLOCK.)

我没有解释的另一个细微之处是,可以在一个方向上关闭数据传递,同时允许它在另一个方向继续(如果你关心这一点,请参阅关闭(2))。

您将客户端套接字放在write描述符集中。您需要将它们放在read描述符集中。

当服务器套接字至少有一个挂起的客户端请求时,它是可读的。您可以调用accept()来接受客户端。

当套接字的入站缓冲区中有数据,或者其连接的对等方已断开连接时,它是可读,而不是可写。您可以调用read()进行区分。read()在入站数据时返回>0,在正常断开连接时返回0,在出错时返回-1。

当套接字的出站缓冲区中有可用空间时,它是可写的。如果write()失败并出现EWOULDBLOCK错误,则出站缓冲区已满,套接字不再可写。当缓冲区清空一些空间时,套接字将再次变为可写

此外,select()会修改传递给它的fdsets,因此需要在每次循环迭代中重置rfds。为了避免这种情况,您可以使用(e)poll()

所以,你需要更像这样的东西:

fd_set rfds;
while (!serverStop)
{
    FD_ZERO(&rfds);
    FD_SET(serverFd, &rfds);
    fillWithClientFds(&rfds); // clients only listen for messages
    if (select(notimportant, &rfds, NULL, NULL, NULL) < 0)
        break;
    if (FD_ISSET(serverFd, &rfds)) // new client appeared
    {
        // call accept(), add client to connected list...
    }
    // clear disconnected list...
    for (each client in connected list)
    {
        if (FD_ISSET(clientFd, &rfds))
        {
            int nBytes = read(clientFd, ...);
            if (nBytes > 0)
            {
                // handle client data as needed ...
            }
            else if (nBytes == 0)
            {
                // add client to disconnected list
            }
            else
            {
                // handle error...
                // possibly add client to disconnected list...
            }
        }
    }
    for (each client in disconnected list)
    {
        // remove client from connected list...
    }
    for (each client in disconnected list)
    {
        // inform connected clients
    }
}

相关内容

  • 没有找到相关文章

最新更新