Смущает поведение функции отключения (fd, параметры) - PullRequest
2 голосов
/ 05 апреля 2019

Я тестирую свой код сокета, который используется для передачи текстового файла, и пишу этот код, ссылаясь на книгу Сетевое программирование Unix (китайская версия).Вкратце я вставлю следующий код:

Моя функция serve_client:

void serve_client(int connfd, const char *filename, size_t filesize)
{
    char header[1024];
    int fd = open(filename, O_RDONLY, 0);
    char *file_mapped;
    if (fd == -1)
    {
        char *not_found = "HTTP/1.1 404 NOT FOUND\r\n";
        send(connfd, not_found, strlen(not_found), 0);
    }
    else
    {
        sprintf(header, "HTTP/1.1 200 OK\r\n");
        sprintf(header, "%sContent-Length: %u\r\n", header, filesize);
        sprintf(header, "%sContent-Type: text/plain; charset=utf-8\r\n\r\n", header);
        // send http response header
        send(connfd, header, strlen(header), 0);

        printf("Response headers:\n");
        printf("%s", header);

        file_mapped = (char *)mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
        close(fd);

        // send http response body
        send(connfd, file_mapped, filesize, 0);
        int unmapped = munmap(file_mapped, filesize);
        if (unmapped == -1)
        {
            perror("memory unmapped failed!");
            _exit(1);
        }
    }
}

Есть несколько вопросов, которые я хотел бы задать вам, ребята:

  1. После того, как эта serve_client() функция успешно вернется, я имею в виду, что по крайней мере данные, которые мне нужны, должны быть полностью скопированы в буфер ядра, чтобы быть отправленными в ближайшем будущем.Я прав насчет этого?

  2. shutdown() функция вызывается, как показано ниже:

    serve_client(connfd, path, st.st_size);
    shutdown(connfd, SHUT_WR); 
    // thread or process ends
    

Я проверяю советы, упомянутые в этой книге, это говорит о том, что эта функция с этой опцией SHUT_WR приведет к тому, что данные, оставшиеся в буфере ядра, будут сначала отправлены, а затем окончательный FIN.Это правильно?

Я фиксирую данные, отправленные и полученные с помощью WireShark, как показано на фотографии ниже: https://i.imgur.com/Xu8gAgh.jpg Я видел, что RST прибыл, до того, как все данные были обнаружены.который не удалось клиенту, например, wget или просто доступ в Интернет.Любой совет был бы великолепен.

Теперь я решил эту проблему, выполнив это, позволив клиенту закрыть соединение, и сервер дождется прибытия FIN.Оно работает.Но все же не то, что я хочу.: (

while (1)
{
    ssize_t bytes_read = recv(connfd, buf, 1024, 0);
    if (bytes_read > 0)
    {
        continue;
    }
    else if (bytes_read == 0)
    {
        close(connfd);
        break;
    }
    else
    {
        // < 0
        // handle error
        close(connfd);
        break;
    }
} 

РЕДАКТИРОВАТЬ Извините за недопонимание, вызванное этим вопросом, дамп показал RST, отправленный с сервера, что похоже на то, что мне сказали, что процесс преждевременно завершилсяЭто причина того, что предыдущий код не сработает. Спасибо за все ваши объяснения, которые действительно помогают мне лучше понять прогресс под капотом.

1 Ответ

1 голос
/ 05 апреля 2019

Завершение процесса неявно close() s все дескрипторы файлов / сокетов.И это проблема.Закрытие после отправки может привести к потере данных на стороне получателя (в зависимости от реализации стека TCP).

Необходимо реализовать протокол уровня приложения, в котором клиент подтверждает получение всех данных, прежде чем сервер сможет закрыть сокет.

Подводя итог: Использование закрытия сокета как части протокола прикладного уровня не является надежным .Не делай этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...