#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: смотрите обновленный ответ. В вашем коде есть не только неправильные ожидания, но и реальные ошибки.