众所周知,Http协议是基于Tcp协议的基础上产生的浏览器到服务器的通信协议 ,其根本原理也是通过socket进行通信。
使用HTTP协议通信,需要注意其返回的响应报文格式不能有任何问题。
响应报文,一共包括4个部分,分别是响应行,响应头,空行,响应体,并且每项数据之间必须使用/r/n隔开。
空行是区分响应头和响应体的必要数据,不能省略。
HTTP静态Web服务器主要开发思路如下:
1.导入socket模块
2.创建socket对象
3.设置端口复用,解决端口阻塞问题
4.绑定端口及ip,在绑定端口及IP后,客户端只能通过绑定的IP及端口给服务器发送请求报文。
5.设置监听,
注意:设置监听成功后,原socket变成被动套接字,不能够进行数据的收发。
6.等待客户端(浏览器)链接(发送请求)
7.使用链接成功后返回的新socket进行数据的收发。
注意:此处返回数据应为HTTP响应报文。
1 # 1.导入模块 2 import socket 3 4 5 def main(): 6 # 2.创建socket对象 7 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 # 3.设置端口复用 10 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 11 # 4.绑定端口 12 server_socket.bind(('', 8001)) 13 # 5.设置监听 14 server_socket.listen(128) 15 # 设置循环接收客户端连接,实现多客户端连接 16 while True: 17 # 6.接收客户端连接 18 client_socket, ip_port = server_socket.accept() 19 print("客户端:%s 上线了,使用端口为:%s" % ip_port) 20 # 7.接收数据 21 recv_data = client_socket.recv(1024).decode('utf-8') 22 if recv_data: 23 # print('接收的数据为:', recv_data) 24 # 获取http请求报文中的指定路径 25 # split()方法不指定参数时,默认以空白字符( , ,空格)分割 26 # 获取到的路径信息分割后,会形成三部分存放到列表中 27 # 1.请求提交的方式:GET/POST 28 # 2.请求路径信息及参数信息 29 # 3.HTTP协议及版本 30 page_recv_data = recv_data.split()[1] 31 print('请求的资源路径为:', page_recv_data) 32 # 判断接受到的路径信息是否包含参数 33 # HTTP协议中,参数格式为:/index.html?name=666&age=12 34 if '?' in page_recv_data: 35 real_recv_page = page_recv_data.split('?')[0] 36 else: 37 real_recv_page = page_recv_data 38 try: 39 # 8.发送数据 40 41 # 接收指定的路径信息,并读取文件信息 42 # 注意f-string只能在3.6及以上版本使用 43 data = f'static{real_recv_page}' 44 print(data) 45 with open(data, 'rb') as file: 46 page_data = file.read() 47 except Exception as e: 48 # 8.1 当文件不存在时,编写HTTP协议如下格式: 49 http_line = 'HTTP/1.1 / 404 NOT FOUND ' 50 http_header = 'Server: PWS/1.0 ' 51 http_body = '<h1>Page Not Found!</h1>' 52 send_data = (http_line + http_header + ' ' + http_body).encode() 53 client_socket.send(send_data) 54 else: 55 # 8.1 当文件存在时,编写HTTP协议如下格式: 56 http_line = 'HTTP/1.1 / 200 ok ' 57 http_header = 'Server: PWS/1.0 ' 58 send_data = (http_line + http_header + ' ').encode() + page_data 59 client_socket.send(send_data) 60 finally: 61 # 断开与客户端连接 62 client_socket.close() 63 else: 64 print('客户端:%s,端口号:%s 下线了' % ip_port) 65 break 66 67 # 9.关闭套接字 68 # 关闭服务器 69 # server_socket.close() 70 71 72 # 入口 73 if __name__ == '__main__': 74 main()