Unix сетевое программирование разъяснения

Я изучал классическую книгу " Сетевое программирование Unix", когда наткнулся на эту программу (раздел 6.8, стр. 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. Цитирую из книги,

"К сожалению, существует проблема с сервером, который мы только что показали. Рассмотрим, что произойдет, если злонамеренный клиент подключится к серверу, отправит один байт данных (кроме новой строки), а затем перейдет в спящий режим. Сервер вызовет чтение (системный вызов), который будет считывать один байт данных от клиента, а затем блокировать следующий вызов для чтения, ожидая получения дополнительных данных от этого клиента. Сервер будет заблокирован этим одним клиентом и не будет обслуживать никаких другие клиенты, пока вредоносный клиент не отправит новую строку или не прекратит работу

Я не уверен, правильно ли я это понимаю. Почему системный вызов read будет вызван во второй раз для этого вредоносного клиента, поскольку он отправил только 1 байт данных, который получает уведомление при первом вызове select. Последующие вызовы select никогда не будут иметь этот вредоносный дескриптор файла, так как нет активности. Я что-то здесь упускаю?

Я предполагаю, что в коде есть опечатка, а не Read, это должна быть какая-то версия метода Readline, упомянутая в других местах книги.

Примечание: код содержит Read и Select (с заглавными буквами R и S), которые являются ничем иным, как обработчиками ошибок обработчиков системного вызова read и select.

2 ответа

Решение

Да, похоже, что это было задумано Readline,

В загружаемом исходном коде этот файл tcpcliserv/tcpservselect01.c и есть соответствующий .lc файл (с примечаниями к номеру строки), который использует Readline вместо Read, и это было Readline во втором издании книги ( исходный код). Единственный способ понять смысл заключенного в скобки комментария "(кроме новой строки)" - это предположить, что предполагаемая функция чтения читает до новой строки.

Как ни странно, об этом не сообщалось. Может быть, вы должны сделать это.

Я думаю, что проблема, на которую он указывал, заключалась в том, что, как вы отметили в своем ПРИМЕЧАНИЕ, этот код использует Read который является оберткой read, Полагаю, поскольку я не собираюсь сейчас копать свою книгу, Read постараюсь позвонить read второй раз, чтобы закончить получать данные, которые никогда не приходят.

Другие вопросы по тегам