首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >unp图书单线程服务器使用select

unp图书单线程服务器使用select
EN

Stack Overflow用户
提问于 2015-01-26 22:23:24
回答 1查看 71关注 0票数 0

在第6章"I/O多路复用:选择和轮询功能“的"UNIX网络编程”第3卷第1卷6.8节"TCP Echo Server (Revisited)“一书中,该书写道:

“不幸的是,我们刚刚展示的服务器出现了问题。考虑一下,如果恶意客户端连接到服务器,发送一个字节的数据(换行符除外),然后进入睡眠状态,会发生什么情况。服务器将调用read,它将从客户端读取单字节的数据,然后阻塞下一个读取调用,等待来自该客户端的更多数据。然后,服务器被这个客户端阻塞(‘挂起’可能是一个更好的术语),并且不会服务于任何其他客户端(无论是新的客户端连接还是现有客户端的数据),直到恶意客户端发送换行符或终止为止。

然而,我怀疑这不是书中描述的情况。如果在第二次调用select()函数时“恶意”客户机处于休眠状态,则相应的套接字描述符将不会处于可读状态,因此read()函数永远不会有机会阻塞单线程服务器。为了验证这一点,我运行了示例服务器和一个“恶意”客户端,结果发现该服务器没有被阻塞,并且正常地与其他客户端对应。

我承认,在结合使用select()或epoll()等I/O多路复用调用时,建议使用非阻塞I/O。但我的问题是,本书的结论有什么问题吗?或者在实际应用中可能发生的情况,而不是这个简单的例子?还是我的代码有问题?非常感谢!

示例服务器代码(tcpservselect01.c):

代码语言:javascript
复制
#include "unp.h"
int
main(int argc, char **argv)
{
    int     i, maxi, maxfd, listenfd, connfd, sockfd;
    int     nready, client[FD_SETSIZE];
    ssize_t n;
    fd_set  rset, allset;
    char    buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in  cliaddr, servaddr;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(SERV_PORT);

    Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

    Listen(listenfd, LISTENQ);

    maxfd = listenfd;           /* initialize */
    maxi = -1;                  /* index into client[] array */
    for (i = 0; i < FD_SETSIZE; i++)
        client[i] = -1;         /* -1 indicates available entry */
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);
    for ( ; ; ) {
        rset = allset;      /* structure assignment */
        nready = Select(maxfd+1, &rset, NULL, NULL, NULL);

        if (FD_ISSET(listenfd, &rset)) {/* new client connection */
            clilen = sizeof(cliaddr);
            connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);

            for (i = 0; i < FD_SETSIZE; i++)
                if (client[i] < 0) {
                    client[i] = connfd; /* save descriptor */
                    break;
                }
            if (i == FD_SETSIZE)
                err_quit("too many clients");

            FD_SET(connfd, &allset);/* add new descriptor to set */
            if (connfd > maxfd)
                maxfd = connfd;         /* for select */
            if (i > maxi)
                maxi = i;           /* max index in client[] array */

            if (--nready <= 0)
                continue;       /* no more readable descriptors */
        }

        for (i = 0; i <= maxi; i++) {/* check all clients for data */
            if ( (sockfd = client[i]) < 0)
                continue;
            if (FD_ISSET(sockfd, &rset)) {
                if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {
                    /*4connection closed by client */
                    Close(sockfd);
                    FD_CLR(sockfd, &allset);
                    client[i] = -1;
                } else
                    Writen(sockfd, buf, n);

                if (--nready <= 0)
                    break;  /* no more readable descriptors */
            }
        }
    }
}

“恶意”客户端代码

代码语言:javascript
复制
#include    "unp.h"

void
sig_pipe(int signo)
{
    printf("SIGPIPE received\n");
    return;
}

int
main(int argc, char **argv)
{
    int                 sockfd;
    struct sockaddr_in  servaddr;

    if (argc != 2)
        err_quit("usage: tcpcli <IPaddress>");

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(9877);
    Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

    Signal(SIGPIPE, sig_pipe);

    Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));

    Write(sockfd, "h", 1);
    printf("go to sleep 20s\n");
    sleep(20);
    printf("wake up\n");
    printf("go to sleep 20s\n");
    Write(sockfd, "e", 1);
    sleep(20);
    printf("wake up\n");

    exit(0);
}
EN

回答 1

Stack Overflow用户

发布于 2015-01-27 01:47:32

赞成。这本书关于DOS的结论是错误的。首先,本书的示例服务器代码没有假设输入数据应由N字节组成或以换行符结尾,因此不带换行符的单字节输入应该不会对服务器造成任何损害。

  • Google books link to the relevant page
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28151949

复制
相关文章

相似问题

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