Unix网络编程说明 [英] Unix Network Programming Clarification

查看:126
本文介绍了Unix网络编程说明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读经典书籍 Unix网络编程,当我偶然发现此程序时(第6.8节,第179-180页)

I was going through the classic book Unix Network Programming, when I stumbled upon this program (Section 6.8, page 179-180)

#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 */
            }
        }
    }
}    

作者提到此程序对DOS攻击并不安全。从书中引用

The author mentions that this program is not safe against DOS attack. Quoting from the book,

不幸的是,我们刚刚展示的服务器存在问题。请考虑一下,如果恶意客户端连接到服务器,会发生什么情况,发送一个字节的数据(而不是换行符),然后进入睡眠状态,服务器将调用 read (系统调用),系统将从客户端读取单个数据字节,然后进行阻止在下一次调用 read 的过程中,等待来自此客户端的更多数据。然后,该服务器被该客户端阻止,除非恶意客户端发送换行符或终止,否则该服务器将不再为其他客户端提供服务。 / em>

"Unfortunately, there is a problem with the server that we just showed. Consider what happens if a malicious client connects to the server, sends one byte of data (other than a newline), and then goes to sleep. The server will call read (system call), which will read the the single byte of data from the client and then block in the next call to read, waiting for more data from this client. The server is then blocked by this one client, and will not service any other clients until malicious client either sends a newline or terminates"

我不确定我是否理解正确。为什么第二次调用此恶意客户端的 read 系统调用,因为它仅发送了1字节的数据,而第一次调用 select 会通知该数据。后续对 select 的调用将永远不会设置此恶意文件描述符,因为没有活动。我在这里遗漏了什么吗?

I am not sure if I understand this correctly. Why will the read system call be called the second time for this malicious client, since it only sent 1 byte of data, that gets notified by the first call to select. The subsequent calls to select will never have this malicious file descriptor set as there is no activity. Am I missing something here?

我的猜测是代码中有错别字,而不是Read,应该是其他地方提到的Readline方法的某个版本在书里。

My guess here is that there is a typo in the code, instead of Read, it should be some version of Readline method mentioned at other places in the book.

注意:该代码包含 Read Select (大写的R和S ),它们不过是由 read select 系统调用

Note: The code contains Read and Select (with capital R and S), which are nothing but error handled wrappers of read and select system call

推荐答案

是的,似乎原本打算是 Readline

Yes, it seems likely that it was intended to be Readline.

可下载的源代码该文件为 tcpcliserv / tcpservselect01.c 并且有一个相应的 .lc 文件(带有行号注释),该文件使用 Readline 而不是阅读,在本书第二版中是 Readline 源代码)。理解括号注释(除了换行符)的唯一方法是假设预期的读取函数可以读取换行符。

In the downloadable source code that file is tcpcliserv/tcpservselect01.c and there is a corresponding .lc file (with line number annotations) which uses Readline instead of Read, and it was Readline in the second edition of the book (source code). About the only way to make sense of the parenthetic comment "(other than a newline)" is to assume that the intended read function reads up to a newline.

奇怪的是,尚未在勘误表中 进行举报。也许您应该这样做。

Oddly, it hasn't been reported in the errata. Maybe you should do so.

这篇关于Unix网络编程说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆