Почему файл style.css не поставляется в том же TCP-соединении, когда я использую протокол http1.1?

#python #html #sockets #protocols #python-sockets

#питон #HTML #розетки #протоколы #python-сокеты

Вопрос:

Я использую сокет python для написания постоянного http-сервера. Я думаю, что файл style.css должен передаваться через тот же номер порта, но, похоже, я не получил результата. Пакеты № 48 и 49 показывают, что файл style.css передается через другой порт по сравнению с пакетом 37.

Я думаю, что в заголовке res_for_good может быть что-то не так.

 import socket from datetime import datetime import threading  res_for_good = '''HTTP/1.1 200 OKr Date: Sun, 18 Oct 2012 10:36:20 GMTr Accept-Ranges: bytesr Content-Type: text/html; charset=iso-8859-1r Connection: keep-aliver Keep-Alive: timeout=3 max=5r Content-Length: 112r r lt;headgt; lt;link rel="stylesheet" href="./style.css" type="text/css"gt; lt;/headgt; lt;htmlgt; lt;bodygt;good HaHalt;/bodygt; lt;/htmlgt; '''  res_for_notfound='''HTTP/1.1 404 Not Foundr Date: Sun, 18 Oct 2012 10:36:20 GMTr Accept-Ranges: bytesr Content-Type: text/html; charset=iso-8859-1r Connection: keep-aliver Keep-Alive: timeout=3 max=5r Content-Length: 116r r lt;headgt; lt;link rel="stylesheet" href="./style.css" type="text/css"gt; lt;/headgt; lt;htmlgt; lt;bodygt;404 Not Foundlt;/bodygt; lt;/htmlgt; '''  res_for_style='''HTTP/1.1 200 OKr Date: Sun, 18 Oct 2012 10:36:20 GMTr Accept-Ranges: bytesr Content-Type: text/css; charset=iso-8859-1r Keep-Alive: timeout=3 max=5r Connection: keep-aliver Content-Length: 46r r body{  color: red;  font-size: 100px; } '''  def serveClient(clientsocket, address):  start = datetime.now()  objcount=0  # we need a loop to continuously receive messages from the client  while True:  objcount =1    # then receive at most 1024 bytes message and store these bytes in a variable named 'data'  # you can set the buffer size to any value you like  data = clientsocket.recv(1024)  data_utf8=data.decode('utf-8').split('rn')  #data_json = json.loads(data_utf8)  print(address)  print(data)        # if the received data is not empty, then we send something back by using send() function  if '/good.html' in data_utf8[0]:  clientsocket.sendall(res_for_good.encode())     if '/style.css' in data_utf8[0]:  print("transfer css")  #res="Content-Type: text/cssnn" css_file.read()  res=res_for_style  clientsocket.sendall(res_for_style.encode())    if '/redirect.html' in data_utf8[0]:  clientsocket.sendall(res_for_redirect.encode())  elif data:  clientsocket.sendall(res_for_notfound.encode())     if data == b'':  objcount-=1    print("object count: " str(objcount))  now = datetime.now()  # we need some condition to terminate the socket  # lets see if the client sends some termination message to the server  # if so, then the server close the socket   if objcount == max_rec_Object or (now-start).total_seconds()gt;waiting_time:  print(start)  print(now)  print('close socket')  clientsocket.close()  break  while True:  # accept a new client and get it's informati   # print(socket.gethostbyaddr(s.getpeername))   (clientsocket, address) = s.accept()  # create a new thread to serve this new client  # after the thread is created, it will start to execute 'target' function with arguments 'args'   threading.Thread(target = serveClient, args = (clientsocket, address)).start()  

что я получаю в проволочной акуле

Ответ №1:

Я думаю, что файл style.css должен передаваться через тот же номер порта

Во-первых, в HTTP/1.1 нет требования, которое говорит об этом. Кроме того, в вашем коде есть ошибки.

Сначала ошибки: как видно из захвата пакетов, ваш сервер отвечает на один запрос /good.html 3 HTTP-ответами: один-ожидаемый 200, два других-неожиданные 404. Первый неправильный 404 связан с этим кодом:

 if '/good.html' in data_utf8[0]:  clientsocket.sendall(res_for_good.encode())  ...  if '/redirect.html' in data_utf8[0]:  clientsocket.sendall(res_for_redirect.encode())  elif data:  clientsocket.sendall(res_for_notfound.encode())   

Поскольку он не останавливается после обработки /good.html , он в конечном итоге окажется в последней показанной строке и отправится res_for_notfound .

Вторая ошибка 404 связана с этим кодом:

хотя верно: … данные = clientsocket.recv(1024) … данные elif: клиентский карман.отправить вызов(res_for_notfound.encode())

Здесь слепо предполагается, что запрос не превысит 1024 и что он будет прочитан в течение одного recv . Оба предположения неверны. Из захвата пакета видно, что запрос на самом деле составляет 1098 байт (посмотрите на ACK=1099). И даже если бы он был меньше 1024 , не было бы никакой гарантии, что он будет прочитан в пределах одного recv , TCP работает не так.

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


Тем не менее, даже при правильном ответе не будет никакой гарантии, что второй запрос поступит через то же TCP-соединение. Явное или неявное объявление поддержки HTTP keep alive просто означает, что клиент и сервер поддерживают повторное использование TCP — соединения для другого HTTP-запроса. Это не означает, что для следующего запроса необходимо использовать конкретное существующее TCP-соединение или что вообще необходимо использовать какое-либо существующее TCP-соединение вместо создания нового.

Из захвата пакетов видно, что браузер изначально открывает два TCP-соединения с сервером. Это не редкость, так как обычно сайт включает в себя множество ресурсов, которые следует извлекать как можно быстрее. Только HTTP/1.1 может только последовательно, а не параллельно извлекать ресурсы по одному TCP-соединению. Поэтому неплохо иметь наготове еще одно запасное TCP — соединение. Это другое уже существующее соединение затем используется в вашем случае для нового ресурса.

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

1. Но почему tcp-соединение закрывается под номером 43.

2. @Ying: смотрите обновленный ответ. В вашем коде есть не только неправильные ожидания, но и реальные ошибки.