首页 > 解决方案 > select() 是否可以为没有排队数据的套接字返回准备就绪?

问题描述

我正在阅读 R.Stevens 的 UNIX Network Programming,以下仅包含相关部分的代码片段取自其中。它是一个回声服务器。

fd_set rset, allset;
int nready, client[FD_SETSIZE];
...
for( ; ; ) {
    rset = allset;
    nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
    ....
    for( i = 0; i <= maxi; i++){
        if ( (sockfd = client[i]) <= 0)
            continue;
        if (FD_ISSET(sockfd, &rset)){
            if( (n = read(sockfd, buf, MAXLINE)) == 0){
                close(sockfd);
                FD_CLEAR(sockfd, &allset);
                client[i] = -1;
            } else
                writen(sockfd, buf, n);
            ...
            }
        }

我将简要描述变量:client是一个包含分配给连接客户端的文件描述符的数组;-1 代表自由进入。是准备读取的fdnready的数量。是一个保存位的结构,用于指定哪个fd已准备就绪。是一个相同类型的结构,表示必须由 测试的fdrsetallsetselect()

内部for循环检查来自每个连接的客户端的传入数据(这通过 FD_ISSSET 宏进行测试)。如果有任何待处理的数据,服务器会将其写回客户端。如果read()返回 0,则表示客户端已向服务器发送了 FIN,因此它终止与 的连接close()

现在的问题是:作者说我刚刚展示的服务器有问题。事实上,考虑一个连接到服务器的恶意客户端,发送一个字节的数据,而不是换行符,然后进入睡眠状态。服务器将调用read(),读取该字节,然后阻止对 的下一次调用read(),等待来自该客户端的更多数据,从而拒绝向所有其他客户端提供服务。我不明白为什么服务器应该在下一次调用read(): 之前阻塞,在下一次调用之前read()select()将返回每个连接的套接字的就绪状态,并且由于我们的客户端没有发送更多数据(一个字节已经被消耗),未设置此客户端的就绪状态位。因此,if没有输入客户端的块,并且read()不叫。这很好,除非select()可以为没有数据排队的套接字返回准备就绪,我认为这是不可能的。那么我错在哪里?

标签: cnetworkingserverposix

解决方案


推荐阅读