http協議、web伺服器、併發伺服器(上)
阿新 • • 發佈:2018-12-26
目錄
- 1. HTTP格式
- 2. Web靜態伺服器-顯示固定的頁面
- 3. Web靜態伺服器-顯示需要的頁面
- 4. Web靜態伺服器-多程序版
- 5. Web靜態伺服器-多執行緒版
- 6. Web靜態伺服器-gevent版
1. HTTP格式
每個HTTP請求和響應都遵循相同的格式,一個HTTP包含Header和Body兩部分,其中Body是可選的。HTTP協議是一種文字協議,所以,它的格式也非常簡單。
1.1 HTTP GET請求的格式:
GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
1.2 HTTP POST請求的格式:
POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...
當遇到連續兩個\r\n時,Header部分結束,後面的資料全部是Body。
1.3 HTTP響應的格式:
HTTP/1.1 200 OK Header1: Value1 Header2: Value2 Header3: Value3 body data goes here...
HTTP響應如果包含body,也是通過\r\n\r\n來分隔的。
請再次注意,Body的資料型別由Content-Type頭來確定,如果是網頁,Body就是文字,如果是圖片,Body就是圖片的二進位制資料。
當存在Content-Encoding時,Body資料是被壓縮的,最常見的壓縮方式是gzip,所以,看到Content-Encoding: gzip時,需要將Body資料先解壓縮,才能得到真正的資料。壓縮的目的在於減少Body的大小,加快網路傳輸。
2. Web靜態伺服器-顯示固定的頁面
import socket def handle_client(new_client): """處理客戶端請求""" recv_data = new_client.recv(1024) print(recv_data) # 組裝響應的內容 response_headers = "HTTP/1.1 200 OK\r\n" response_headers += "\r\n" response_body = "6666" response = response_headers + response_body new_client.send(response.encode("utf-8")) new_client.close() def main(): # 建立套接字 tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 繫結本地訊息 tcp_socket_server.bind(("", 8090)) # 套接字由主動變被動 tcp_socket_server.listen(128) while True: # 接收新的請求 new_client, client_addr = tcp_socket_server.accept() handle_client(new_client) # 關閉套接字 tcp_socket_server.close() if __name__ == "__main__": main()
如上的程式碼僅僅只是向瀏覽器傳送了簡單的文字內容:6666
在瀏覽器中訪問:
3. Web靜態伺服器-顯示需要的頁面
import socket
import re
def handle_client(new_client):
"""處理客戶端請求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 組裝響應的內容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 建立套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 繫結本地訊息
tcp_socket_server.bind(("", 8090))
# 套接字由主動變被動
tcp_socket_server.listen(128)
while True:
# 接收新的請求
new_client, client_addr = tcp_socket_server.accept()
handle_client(new_client)
# 關閉套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
在瀏覽器中訪問:
4. Web靜態伺服器-多程序版
import socket
import re
import multiprocessing
def handle_client(new_client):
"""處理客戶端請求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 組裝響應的內容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 建立套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 繫結本地訊息
tcp_socket_server.bind(("", 8090))
# 套接字由主動變被動
tcp_socket_server.listen(128)
while True:
# 接收新的請求
new_client, client_addr = tcp_socket_server.accept()
p = multiprocessing.Process(target=handle_client, args=(new_client,))
p.start()
new_client.close()
# 關閉套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
5. Web靜態伺服器-多執行緒版
import socket
import re
import threading
def handle_client(new_client):
"""處理客戶端請求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 組裝響應的內容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 建立套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 繫結本地訊息
tcp_socket_server.bind(("", 8090))
# 套接字由主動變被動
tcp_socket_server.listen(128)
while True:
# 接收新的請求
new_client, client_addr = tcp_socket_server.accept()
t = threading.Thread(target=handle_client, args=(new_client,))
t.start()
# 關閉套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
6. Web靜態伺服器-gevent版
import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()
def handle_client(new_client):
"""處理客戶端請求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 組裝響應的內容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 建立套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 繫結本地訊息
tcp_socket_server.bind(("", 8090))
# 套接字由主動變被動
tcp_socket_server.listen(128)
while True:
# 接收新的請求
new_client, client_addr = tcp_socket_server.accept()
g = gevent.spawn(handle_client, new_client)
g.join()
# 關閉套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()