C: Вопрос о сетевом руководстве Биджа ... Есть ли здесь предположение? - PullRequest
2 голосов
/ 02 февраля 2010

Я только что просматривал Руководство по работе с сетями от Beej, и мне любопытно узнать об этой части кода (специально помеченной «Отсюда» и «Здесь»):

// main loop
    for(;;) {
        read_fds = master; // copy it
        if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
            perror("select");
            exit(4);
        }

        // run through the existing connections looking for data to read
        for(i = 0; i <= fdmax; i++) {
            if (FD_ISSET(i, &read_fds)) { // we got one!!
                if (i == listener) {
                    // handle new connections
                    addrlen = sizeof remoteaddr;
                    newfd = accept(listener,
                        (struct sockaddr *)&remoteaddr,
                        &addrlen);

                    if (newfd == -1) {
                        perror("accept");
                    } else {
                        FD_SET(newfd, &master); // add to master set
                        if (newfd > fdmax) {    // keep track of the max
                            fdmax = newfd;
                        }
                        printf("selectserver: new connection from %s on "
                            "socket %d\n",
                            inet_ntop(remoteaddr.ss_family,
                                get_in_addr((struct sockaddr*)&remoteaddr),
                                remoteIP, INET6_ADDRSTRLEN),
                            newfd);
                    }
                } else {
                    // handle data from a client
                    //----------------- FROM HERE --------------------------
                    if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
                        // got error or connection closed by client
                        if (nbytes == 0) {
                            // connection closed
                            printf("selectserver: socket %d hung up\n", i);
                        } else {
                            perror("recv");
                        }
                        close(i); // bye!
                        FD_CLR(i, &master); // remove from master set
                    //----------------- TO HERE ----------------------------
                    } else {
                        // we got some data from a client
                        for(j = 0; j <= fdmax; j++) {
                            // send to everyone!
                            if (FD_ISSET(j, &master)) {
                                // except the listener and ourselves
                                if (j != listener && j != i) {
                                    if (send(j, buf, nbytes, 0) == -1) {
                                        perror("send");
                                    }
                                }
                            }
                        }
                    }
                } // END handle data from client
            } // END got new incoming connection
        } // END looping through file descriptors
    } // END for(;;)--and you thought it would never end!

    return 0;

Теперь я знаю, что read не всегда читает «все», что должно быть прочитано в сокете, и что иногда он может возвращать только часть этого. В таком случае, не будет ли этот код неверным? Я имею в виду, что после одного чтения соединение закрывается ... Вместо этого мы должны иметь какой-то другой механизм на месте? Если да, то какой здесь правильный подход?

Ответы [ 3 ]

4 голосов
/ 02 февраля 2010

Сокет закроется там только в случае ошибки от recv (), иначе он будет иметь дело с данными, которые были прочитаны, даже если они не все прочитаны. Это тогда прочитает больше, когда это повторяется снова. Вы уверены, что это то, что вы спрашиваете?

1 голос
/ 02 февраля 2010

Ваш единственный вызов close, когда recv () вернул отрицательное значение, что означает, что recv имел какую-то ошибку. Обратите внимание, что в блоке, где вы делаете закрытие, есть комментарий с указанием // got error or connection closed by client).

Когда вы фактически получаете некоторые данные (ветвь else, начинающаяся с // we got some data from a client), соединение не закрывается.

Вы правы в том, что не можете предполагать, что данные поступают одновременно. Ваша ошибка в том, что вы следите за тем, как работает код.

1 голос
/ 02 февраля 2010

Да, вы будете продолжать читать, пока не получите все данные, которые ожидали, очевидно, вам нужно каким-то образом знать, чего ожидать - именно поэтому http ставит размер документа на первое место

...