Простой HTTP-сервер, использующий программирование сокетов на С, не работает в Chrome - PullRequest
0 голосов
/ 16 октября 2019

Я пытался написать простой http-сервер, используя сокет-программирование на C. Я хочу сначала попытаться, чтобы сервер мог отправить обратно HTML-файл без учета того, какой запрос был получен.

Вот заголовоки тело:

char httpHeader[100000] = 
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<!DOCTYPE html>\r\n"
"<html><head><title>Testing</title></head>\r\n"
"<body><p>Testing</p></body><html>\r\n";

Вот процедура отправки пакета:

while(1) {
if ( (connfd = accept(listenfd, NULL, NULL) ) < 0 ) {
    fprintf(stderr, "accept error\n");
    exit(EXIT_FAILURE);
}

if (send(connfd, httpHeader, sizeof(httpHeader), 0) == -1) {
    fprintf(stderr, "send error\n");
    exit(EXIT_FAILURE);
};

if ( close(connfd) < 0 ) {
    fprintf(stderr, "close error\n");
    exit(EXIT_FAILURE);
}
}

Я связываю сокет с портом 8080 и использую telnet для проверки, работает он или нет. После запуска сервера и отправки запроса по telnet на той же машине клиентская сторона успешно получила весь пакет без каких-либо ошибок.

Но при попытке подключиться к серверу с помощью Chrome произошел сбой. Ошибка GET: "net :: ERR_CONNECTION_RESET 200 (OK)" обнаружился. Когда я проверял сетевой сеанс в DevTool, я увидел, что Chrome получил заголовок ответа, показывающий «HTTP / 1.1 200 OK Content-Type: text / html; charset = UTF-8», но не увидел файл HTML.

Неправильный ли формат заголовка? Я снова проверяю протокол, но не уверен, что делаю не так.

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Подобные проблемы обычно возникают, когда сервер закрывает соединение, пока клиент еще не прочитал данные. В вашем случае сервер закрывает соединение без чтения запроса от клиента. Но даже если вы прочитали полный запрос, проблема все равно может возникнуть, так как клиент мог отправить несколько запросов (конвейерная передача HTTP).

В стандарте HTTP даже есть рекомендация о том, как правильно выполнить закрытие и, в частности,решает проблему, которую вы получаете. Из RFC 7230, раздел 6.6 «Разрыв» :

Если сервер выполняет немедленное закрытие TCP-соединения, существует значительный риск того, что клиент не сможетпрочитать последний ответ HTTP. Если сервер получает дополнительные данные от клиента по полностью закрытому соединению, например, другой запрос, отправленный клиентом до получения ответа сервера, стек TCP сервера отправит клиенту пакет сброса ;к сожалению, пакет сброса может стереть неподтвержденные входные буферы клиента, прежде чем они будут прочитаны и интерпретированы синтаксическим анализатором HTTP клиента.

Чтобы избежать проблемы сброса TCP, серверы обычно закрывают соединение поэтапно . Во-первых, сервер выполняет половинное закрытие, закрывая только сторону записи соединения чтения / записи. Затем сервер продолжает чтение из соединения до тех пор, пока клиент не получит соответствующее закрытие , или пока сервер не будет достаточно уверен, что его собственный стек TCP получил подтверждение клиента пакета (пакетов), содержащегопоследний ответ сервера. Наконец, сервер полностью закрывает соединение.

Кроме того: настоятельно рекомендуется (СЛЕДУЕТ в стандарте) четко указывать размер тела либо с помощью заголовка Content-length, либоиспользуя chunked Transfer Encoding - вместо того, чтобы просто закрывать соединение. Также настоятельно рекомендуется сообщить клиенту о том, что больше запросов не будет приниматься по этому соединению, добавив заголовок Connection: close.

В целом: HTTP намного сложнее, чем можно подумать, просто взглянув нанесколько примеров. Существует стандарт , который описывает, как должны вести себя клиенты и сервер, и есть причина, по которой этот стандарт длинный. Тем не менее, пожалуйста, следуйте ему, если вы намерены реализовать свой собственный стек HTTP, а не просто использовать существующие реализации.

0 голосов
/ 16 октября 2019

Боюсь, это не так проверено, как хотелось бы, но меня поражает то, что вы не слушаете клиента перед отправкой ему данных. Моя гипотеза заключается в том, что Chrome может обнаружить, что каким-то образом / возможно / добавление получения может иметь значение.

Однако, чтобы быть уверенным, вы можете попробовать использовать Wireshark для отслеживания запроса и сравнения с запросом трафика, отправленным наполный сервер, который должен помочь диагностировать различия.

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