Python实现简易版web服务器

末蓝、 2022-12-31 02:27 326阅读 0赞

1.Python实现简易版web服务器

  1. # coding = utf-8
  2. import socket
  3. import re
  4. import threading
  5. import multiprocessing
  6. import gevent
  7. import sys
  8. from gevent import monkey
  9. # monkey.patch_all()
  10. # 采用多进程时,如果开启monkey.patch_all()会报错,报错信息如下:
  11. # TypeError: Cannot serialize socket object
  12. class HTTPServer(object):
  13. def __init__(self, port):
  14. # 初始化操作,创建属性
  15. self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  16. # 创建TCP 套接字
  17. # 设置地址重用选项 解决由2MSL状态规定(30s到2min内主动断开TCP连接的一方
  18. # 不能立即绑定套接字端口
  19. # )的情况 ---> 理解重新绑定 套接字层面 重用地址选项 1设置 0取消
  20. self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  21. # 绑定 监听
  22. self.server_socket.bind(('', port)) # 需要以元组的形式传入
  23. self.server_socket.listen(128) # 接受客户端连接最大个数
  24. def client_handler(self, client_socket):
  25. # 处理客户端的HTTP请求
  26. # 接受数据
  27. recv_data = client_socket.recv(4096)
  28. # 把字节类型数据转换成字符串类型数据,方便切割
  29. recv_str_data = recv_data.decode()
  30. # 请求报文中---》请求行[资源请求路径]
  31. # print(recv_data)
  32. data_set = recv_str_data.split("\r\n")
  33. # print(data_set)
  34. # 请求行
  35. request_line = data_set[0]
  36. print(request_line)
  37. # GET /index2.html HTTP/1.1
  38. result = re.match(r'\w+\s+(\S+)', request_line)
  39. if not result:
  40. print("HTTP请求报文格式错误")
  41. client_socket.close()
  42. return
  43. # 根据正则结果对象取出第一个分组--请求的资源路径
  44. path_info = result.group(1)
  45. print("接受到用户的资源请求 %s" % path_info)
  46. # 回数据
  47. # 根据用户替换的资源路径 读取本地的网页资源
  48. # /home/python/Desktop/1.jpg
  49. # static/index.html
  50. if path_info == '/':
  51. # 用户请求/获取意味着 获取网站首页 web服务器通用规则
  52. path_info = '/index.html'
  53. try:
  54. file = open("./static" + path_info, 'rb')
  55. file_data = file.read() # 如果文件大 可能有隐患
  56. file.close()
  57. except Exception as e:
  58. # 响应行
  59. response_line = "HTTP/1.1 404 Not Found\r\n"
  60. # 响应头
  61. response_header = "Server: PythonWebServer 5.0\r\n"
  62. response_body = "ERROR: file not found!!!"
  63. response_data = response_line + response_header+"\r\n"+response_body
  64. client_socket.send(response_data.encode())
  65. else:
  66. # 响应行
  67. response_line = "HTTP/1.1 200 OK\r\n"
  68. # 响应头
  69. response_header = "Server: PythonWebServer 5.0\r\n"
  70. # 响应体-服务器存储给浏览器发送的资源文件数据
  71. response_body = file_data
  72. # 拼接HTTP响应报文数据
  73. response_data = (response_line+response_header+"\r\n").encode() + response_body
  74. client_socket.send(response_data)
  75. finally:
  76. # 关闭套接字
  77. client_socket.close()
  78. def start_threading(self):
  79. # 多线程启动
  80. while True:
  81. # 接受客户端请求
  82. client_socket, client_addr = self.server_socket.accept()
  83. print("接受到来自%s的链接请求" % str(client_addr))
  84. # 每接受一个客户端连接,创建一个线程,为客户服务
  85. thread = threading.Thread(target=self.client_handler, args=(client_socket,))
  86. # 运行线程
  87. thread.start()
  88. def start_processing(self):
  89. # 多进程启动
  90. while True:
  91. # 接受客户端请求
  92. client_socket, client_addr = self.server_socket.accept()
  93. print("接受到来自%s的链接请求" % str(client_addr))
  94. # 每接受到一个客户端连接 创建一个进程 为客户服务
  95. # 创建一个进程的执行计划
  96. process = multiprocessing.Process(target=self.client_handler, args=(client_socket,))
  97. # 创建并且运行线程
  98. process.start()
  99. # 由于父进程在创建子进程的时候,完全复制了父进程的系统资源
  100. # 将父进程中的client_socket资源释放
  101. client_socket.close()
  102. def start_gevent(self):
  103. # 协程版启动
  104. while True:
  105. # 接受客户端请求
  106. client_socket, client_addr = self.server_socket.accept()
  107. print("接受到来自%s的链接请求" % str(client_addr))
  108. # 每接受到一个客户端连接,创建一个协程并运行,为客户服务
  109. gevent.spawn(self.client_handler, client_socket)
  110. def main():
  111. # 保存命令行参数的列表,每个元素都是字符串类型
  112. # print(sys.argv)
  113. # 第0个元素是程序名,第1个元素是参数--端口
  114. if len(sys.argv) < 2:
  115. print("参数错误: 请使用类似于 python web.py 8888")
  116. return
  117. port = int(sys.argv[1])
  118. http_server = HTTPServer(port)
  119. # 协程启动,启动时需要开启程序顶部的:monkey.patch_all()
  120. # http_server.start_gevent()
  121. # 多进程启动
  122. # http_server.start_processing()
  123. # 多线程启动
  124. http_server.start_threading()
  125. if __name__ == "__main__":
  126. main()

发表评论

表情:
评论列表 (有 0 条评论,326人围观)

还没有评论,来说两句吧...

相关阅读