Как правильно обработать запрос клиента «Подключение: закрыть» на файловом сервере HTTP?

#java #http

#java #http

Вопрос:

Как мне правильно обработать поле запроса клиента Connection: close ? На данный момент, если я получаю это конкретное поле, я закрываю сокет и жду следующего запроса от клиента, затем снова отвечаю и начинаю обслуживать данные.

Я не знаю, почему моя связь клиент-сервер не работает как сервер Apache, с которым я тестировал.

Спасибо за любые разъяснения…

Связь между клиентом и сервером:

 CLIENT:
HEAD /stream.mpeg HTTP/1.0
Host: 127.0.0.1
User-Agent: SuperPlayer
Connection: Close

SERVER:
HTTP/1.0 200 OK 
Date: Wed, 1 Jun 2011 20:05:13 GMT
Server: HTTP Server
Last-Modified: Mon, 06 Aug 2009 01:02:23 GMT
Accept-Ranges: bytes
Connection: Close
Content-Type: audio/mpeg

CLIENT:
HEAD /stream.mpeg HTTP/1.0
Host: 127.0.0.1
User-Agent: SuperPlayer
Connection: Close

SERVER:
HTTP/1.0 200 OK 
Date: Wed, 1 Jun 2011 20:05:13 GMT
Server: HTTP Server
Last-Modified: Mon, 06 Aug 2009 01:02:23 GMT
Accept-Ranges: bytes
Connection: Close
Content-Type: audio/mpeg

231489172304981723409817234981234acvass123412323
21312hjdfaoi8w34yorhadl4hi8rali45mhalo3i,wmotw
345fqw354aoicu43yocq2i3hr
  

Связь клиента с ApacheServer:

 CLIENT:
GET /test.mp3 HTTP/1.0
Host: 192.168.1.120
User-Agent: SuperPlayer
Connection: Close

SERVER:
HTTP/1.1 200 OK
Date: Wed, 01 Jun 2011 19:15:11 GMT
Server: Apache/2.2.16 (Win32)
Last-Modified: Thu, 29 Apr 2010 21:06:34 GMT
ETag: "14000000047049-4f75c8-4856680636a80"
Accept-Ranges: bytes
Content-Length: 5207496
Connection: close
Content-Type: audio/mpeg

...d.....<).0.. ..........<.@.. ( .h.$.J...1...i....A. ......c....a.9..!g.N...A. ........ ....>......|.......8....a......|..|N.............'>........?...C.....@..TJt.n .e...r.iL..#..IH...pR|.
  

Ответ №1:

Да, закрытие сокета — это правильное действие. Если клиент правильно использует этот заголовок, он закрывает сокет на своей стороне, как только получит ваш ответ.

Что я здесь замечаю, так это то, что ваш сервер не возвращает Content-Length заголовок. Несмотря на то, что клиент выдает запрос HEAD, основанный на предложении W3C (раздел 9.4):

Метаинформация, содержащаяся в заголовках HTTP в ответ на запрос HEAD, ДОЛЖНА быть идентична информации, отправленной в ответ на запрос GET. Этот метод может быть использован для получения метаинформации о сущности, подразумеваемой запросом, без передачи самого тела сущности. Этот метод часто используется для проверки гипертекстовых ссылок на действительность, доступность и недавнюю модификацию.

Ответ на запрос HEAD МОЖЕТ быть кэшируемым в том смысле, что информация, содержащаяся в ответе, МОЖЕТ быть использована для обновления ранее кэшированного объекта из этого ресурса. Если новые значения полей указывают на то, что кэшированный объект отличается от текущего объекта (на что указывает изменение длины содержимого, содержимого MD5, ETag или последнего изменения), тогда кэш ДОЛЖЕН рассматривать запись в кэше как устаревшую.

Ключевым моментом здесь является убедиться, что вы сообщаете клиенту размер ответа, фактически не отправляя данные.

Комментарии:

1. Ах! Я не заметил HEAD и GET. Ну, на моем HTTP-сервере я читаю HEAD и получаю запросы, но я не уверен, почему, когда я использовал сервер Apache и собирал данные с помощью Wireshark, я не получал запрос HEAD… Может быть, каким-то образом Wireshark не зафиксировал это?

2. На самом деле я беру свои слова обратно! Да, Wireshark прочитал запрос HEAD … 🙂

3. Я специально игнорирую поле длины. Благодаря вашему сообщению я заметил, что на самом деле была разница в двух запросах клиента. Один HEAD, а другой GET. Теперь я могу прочитать это и правильно обработать запрос клиента.

4. Заголовок просто означает закрыть соединение после отправки ответа.

5. @EJP — это первое, что я говорю в своем ответе. Насколько, по вашему мнению, это оправдывает снижение?

Ответ №2:

Заголовок Connection: close просто означает, что клиент ожидает, что вы закроете соединение после отправки ответа.Это также освобождает вас от необходимости отправлять заголовок Content-Length: .

Ответ №3:

Могу я спросить, почему вы используете http 1.0 в запросе? В http 1.0 не было постоянных подключений, поэтому сервер должен прервать TCP-соединение после ответа, отправляете вы Connection: close или нет.

Комментарии:

1. Да, вы правы, я должен оставить его как http 1.1, чтобы клиент знал, что я поддерживаю постоянное соединение.

Ответ №4:

Если вы используете HTTP 1.0, постоянных подключений нет, как указал alexrs, вместо этого Connection: keep-alive используется HTTP 1.0. На HTTP 1.1 это не нужно, потому что HTTP-соединения по умолчанию являются постоянными на HTTP 1.1.

8.1.2 Общая работа

Существенное различие между HTTP / 1.1 и более ранними версиями HTTP заключается в том, что постоянные соединения используются по умолчанию для любого HTTP-соединения. То есть, если не указано иное, клиент ДОЛЖЕН предполагать, что сервер будет поддерживать постоянное соединение даже после ответов с ошибкой от сервера.

Постоянные соединения предоставляют механизм, с помощью которого клиент и сервер могут сигнализировать о закрытии TCP-соединения. Эта сигнализация выполняется с использованием поля заголовка соединения (раздел 14.10). После того, как был подан сигнал о закрытии, клиент НЕ ДОЛЖЕН отправлять больше запросов по этому соединению.

Вы можете взглянуть на HTTP 1.1 RFC;

RFC для HTTP 1.1