文章目录
1 浏览器网络请求流程
-
浏览器首先链接 DNS 服务器,获取域名对应的 ip 地址
-
通过 ip 和 http 默认端口 80 链接服务器
-
浏览器将请求数据组合成 http 协议的请求文本,发送给服务端
-
服务端收到请求,需要解析请求文本,根据请求资源路径找到对应的资源
-
把资源按照 http 响应格式组成响应文本发送给浏览器
-
浏览器收到响应文本之后进行解析展示
2 搭建静态 web 服务器
1 2 3
| python -m http.server
python3 -m http.server
|
-m 运行模块 __name_以__main_
2.1 Web 服务器开发流程
- 编写一个 TCP 服务端程序
- 获取浏览器发送的 HTTP 请求报文数据
- 读取固定页面数据,把页面数据组装成 HTTP 响应报文数据发送给浏览器。
- HTTP 响应报文数据发送完成以后,关闭服务于客户端的套接字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| import socket import time
if __name__ == '__main__': tcp_server_socekt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socekt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) tcp_server_socekt.bind(("", 8080)) tcp_server_socekt.listen(128)
while True: client_socekt, client_addr = tcp_server_socekt.accept() client_request_data = client_socekt.recv(1024).decode() print(client_request_data) f = open("./static/index.html", "rb") file_data = f.read() response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server:haha\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n").encode() + response_body client_socekt.send(response_data) client_socekt.close()
|
2.2 返回指定页面
解析请求行中的资源路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| client_request_data = client_socekt.recv(1024).decode() if len(client_request_data) <= 1: print("客户端已经关闭") print(client_request_data) else: request_data = client_request_data.split(" ") print(request_data) request_path = request_data[1]
if request_path == "/": request_path = "/index.html"
try: with open("./static" + request_path, "rb") as f: file_data = f.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r\n" response_header = "Server:pwb\r\n" response_body = "404 Not Found sorry" response_data = (response_line + response_header + "\r\n" + response_body).encode()
client_socket.send(response_data) else: response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server:pwb\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n").encode() + response_body
client_socket.send(response_data) finally: client_socket.close()
|
2.3 多任务版服务器
开启多个线程处理接收和发送操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| import socket import threading
def handle_client_request(client_socekt): client_request_data = client_socekt.recv(1024).decode() print(client_request_data) requst_data = client_request_data.split(" ") print(requst_data)
if len(requst_data) == 1: client_socekt.close() return request_path = requst_data[1]
if request_path == "/": request_path = "/index.html"
try: with open("./static" + request_path, "rb") as f: file_data = f.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r\n" response_header = "Server:pwb\r\n" response_body = "404 Not Found sorry" response_data = (response_line + response_header + "\r\n" + response_body).encode()
client_socekt.send(response_data) else: response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server:pwb\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n").encode() + response_body
client_socekt.send(response_data) finally: client_socekt.close()
if __name__ == '__main__': tcp_server_socekt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_server_socekt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) tcp_server_socekt.bind(("", 8080)) tcp_server_socekt.listen(128)
while True: client_socekt, client_addr = tcp_server_socekt.accept() sub_thread = threading.Thread(target=handle_client_request, args=(client_socekt,)) sub_thread.start()
|
关闭浏览器,服务端报错
原因:客户端关闭,服务端 recv 方法不会阻塞,一直读取,读取空数据
1 2 3 4 5
| client_request_data = client_socekt.recv(1024).decode()
if not client_request_data: return
|
2.4 面向对象服务端
- 定义 Server 类
- 在__init__中创建 socket
- 定义 start 开启接收客户端请求
- 客户端请求接收到之后开启新线程执行后续的接收和发送数据操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| import socket import threading
class HttpWebServer: def __init__(self): self.tcp_server_socekt = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.tcp_server_socekt.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.tcp_server_socekt.bind(("", 8080)) self.tcp_server_socekt.listen(128)
def handle_client_request(self, client_socekt): client_request_data = client_socekt.recv(1024).decode() print(client_request_data) request_data = client_request_data.split(" ") print(request_data)
if len(request_data) == 1: client_socekt.close() return request_path = request_data[1]
if request_path == "/": request_path = "/index.html"
try: with open("./static" + request_path, "rb") as f: file_data = f.read() except Exception as e: response_line = "HTTP/1.1 404 Not Found\r\n" response_header = "Server:pwb\r\n" response_body = "404 Not Found sorry" response_data = (response_line + response_header + "\r\n" + response_body).encode()
client_socekt.send(response_data) else: response_line = "HTTP/1.1 200 OK\r\n" response_header = "Server:pwb\r\n" response_body = file_data response_data = (response_line + response_header + "\r\n").encode() + response_body
client_socekt.send(response_data) finally: client_socekt.close()
def start(self): while True: client_socekt, client_addr = self.tcp_server_socekt.accept() sub_thread = threading.Thread(target=self.handle_client_request, args=(client_socekt,)) sub_thread.start()
if __name__ == '__main__': my_web_server = HttpWebServer() my_web_server.start()
|
3 动态端口
获取通过命令行执行 python 文件传递的参数
1 2 3 4 5 6
| import sys
argv = sys.argv if len(argv)==2 and argv[1].isdigit(): print(argv[1])
|
默认没有传递参数,只有一个元素 文件名
sub_thread.start()
if name == ‘main’:
# 创建服务器对象
my_web_server = HttpWebServer ()
# 启动服务器
my_web_server.start ()
1 2 3 4 5 6 7 8 9 10 11 12
|
获取通过命令行执行python文件传递的参数
```python import sys
argv = sys.argv if len(argv)==2 and argv[1].isdigit(): print(argv[1])
|
默认没有传递参数,只有一个元素 文件名