导入必要的模块
import re import socket from multiprocessing import Process
我们导入了re模块用于正则表达式操作,socket模块用于网络通信,以及multiprocessing模块中的Process类用于创建子进程
定义WSGIServer类
class WSGIServer(): def __init__(self, server, port, root): self.server = server self.port = port self.root = root self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.server_socket.bind((self.server, self.port)) self.server_socket.listen(128)
在类的初始化方法__init__中,我们传入了服务器地址server、端口号port和根目录root作为参数,然后创建了一个socket对象server_socket,并设置了一些属性。我们通过bind方法将服务器地址和端口号绑定到server_socket上,并调用listen方法监听连接请求。
处理客户端请求
def handle_socket(self, socket): data = socket.recv(1024).decode('utf-8').splitlines()[0] file_name = re.match(r'[^/]+(/[^ ]*)', data)[1] if file_name == '/': file_name = self.root + '/index.html' else: file_name = self.root + file_name try: file = open(file_name, 'rb') except IOError: response_header = 'HTTP/1.1 404 NOT FOUND \r\n' response_header += '\r\n' response_body = '========Sorry,file not found======='.encode('utf-8') else: response_header = 'HTTP/1.1 200 OK \r\n' response_header += '\r\n' response_body = file.read() finally: socket.send(response_header.encode('utf-8')) socket.send(response_body)
接下来定义了一个handle_socket方法,用于处理客户端发来的请求。首先,我们通过socket.recv方法接收请求数据,并对数据进行解码。然后,使用正则表达式从请求数据中提取出文件名。如果文件名为根目录’/',我们将其设置为根目录下的’index.html’文件,否则拼接上根目录路径。然后,尝试打开对应的文件,如果文件不存在,我们返回404状态码和错误提示信息;如果文件存在,我们返回200状态码和文件内容作为响应体。
最后,我们通过finally块使用socket.send方法将响应头和响应体发送给客户端。
持续监听连接请求
def forever_run(self): while True: client_socket, client_addr = self.server_socket.accept() p = Process(target=self.handle_socket, args=(client_socket,)) p.start() client_socket.close()
在WSGIServer类中,定义了一个forever_run方法,用于持续监听连接请求。在循环中,我们使用accept方法接受客户端的连接请求,并创建一个子进程Process去处理连接请求,以实现多线程并发处理。然后关闭客户端套接字。
主程序入口
if __name__ == '__main__': ip = '0.0.0.0' port = 8899 server = WSGIServer(ip, port, './pages') print('server is running at {}:{}'.format(ip, port)) server.forever_run()
在主程序中,我们实例化了WSGIServer类,并传入服务器地址、端口号和根目录的参数。然后打印出服务器运行的信息,最后调用forever_run方法开始监听连接请求。