• python多任务、面向对象、命令行启动动态绑定端口号静态web服务器代码实现


    一、静态web服务器-多任务

    多任务web服务器:使用多线程,比进程更节省资源,支持多用户同时访问,可以同时处理多个客户端请求

    • 实现步骤
      • 若客户端与服务端建立连接,则创建子线程,使用子线程处理客户端请求,防止主线程阻塞
      • 将创建的子线程设置为守护主线程,防止主线程无法退出

    实现代码

    1. import socket
    2. import threading
    3. def handle_client_request(comm_socket): # 处理客户端请求
    4. recv_data = comm_socket.recv(4096) # 接收请求的二进制数据
    5. if len(recv_data) == 0:
    6. print('未获取到请求数据!')
    7. comm_socket.close()
    8. return
    9. recv_content = recv_data.decode('utf-8') # 对二进制数据解码
    10. print('获取到的数据内容为:', recv_content)
    11. request_list = recv_content.split(" ", maxsplit=2) # 根据指定字符串空格进行分割,最大分割次数为2
    12. request_path = request_list[1] # 获取请求资源路径
    13. print('请求路径为:', request_path)
    14. if request_path == "/": # 判断请求的是否是根目录,若是则返回首页指定数据
    15. request_path = "/index.html"
    16. try:
    17. with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file: # 动态打开指定文件
    18. file_data = file.read() # 读取指定文件数据
    19. except Exception as e: # 请求异常,资源不存在,返回指定404错误数据
    20. with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file: # 打开指定错误文件
    21. error_data = file.read() # 读取指定错误数据
    22. response_line = "HTTP/1.1 404 Not Found!!\r\n" # 响应行
    23. response_header = "Server: PWS1.0 服务器名称及版本……\r\n" # 响应头
    24. response_body = error_data # 响应体
    25. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body # 拼接响应报文
    26. comm_socket.send(response_data) # 发送数据给浏览器
    27. else:
    28. response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
    29. response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
    30. response_body = file_data
    31. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
    32. comm_socket.send(response_data)
    33. finally:
    34. comm_socket.close() # 关闭服务于客户端的套接字
    35. def main():
    36. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP服务端套接字
    37. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置端口号复用,程序退出端口号立即释放
    38. server_socket.bind(("", 9000)) # 绑定端口号
    39. server_socket.listen(128) # 设置监听
    40. while True:
    41. comm_socket, ip_port = server_socket.accept() # 等待接受客户端连接请求
    42. thread = threading.Thread(target=handle_client_request, args=(comm_socket,)) # 若客户端和服务器连接成功,创建子线程
    43. thread.setDaemon(True) # 设置守护主线程
    44. thread.start() # 启动子线程执行对应任务
    45. if __name__ == '__main__':
    46. main()

    输出如下

    1. 获取到的数据内容为: GET /index.html HTTP/1.1
    2. Host: 127.0.0.1:9000
    3. Connection: keep-alive
    4. Cache-Control: max-age=0
    5. sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
    6. sec-ch-ua-mobile: ?0
    7. sec-ch-ua-platform: "Windows"
    8. Upgrade-Insecure-Requests: 1
    9. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
    10. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3;q=0.9
    11. Sec-Fetch-Site: none
    12. Sec-Fetch-Mode: navigate
    13. Sec-Fetch-User: ?1
    14. Sec-Fetch-Dest: document
    15. Accept-Encoding: gzip, deflate, br
    16. Accept-Language: zh-CN,zh;q=0.9
    17. Cookie: csrftoken=1wb7v0r0BQuokJCxRS4JAO2XApvrHXFP90t2PiYb0mz7AwWS0NoKTi0zNaIjOfTl; Hm_lvt_18f619820855042bca58b32408f44de7=1658219884
    18. 请求路径为: /index.html

    浏览器响应如下 

    二、静态web服务器-面向对象 

    • 实现步骤
      • 把提供服务的web服务器抽象为一个类
      • 提供web服务器初始化方法,在方法中创建socket对象
      • 提供一个开启web服务器的方法,让web服务器处理客户端请求操作

    实现代码

    1. import socket
    2. import threading
    3. class HttpWebServer(object): # 定义web服务器类,将提供服务的web服务器抽象为一个类
    4. def __init__(self): # 初始化服务端套接字
    5. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP套接字
    6. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置端口复用,程序退出端口号立即释放
    7. server_socket.bind(("", 9000)) # 绑定端口号
    8. server_socket.listen(128) # 设置监听
    9. self.server_socket = server_socket
    10. @staticmethod
    11. def handle_client_request(comm_socket):
    12. recv_data = comm_socket.recv(4096) # 接收请求的二进制数据
    13. if len(recv_data) == 0:
    14. print('未获取到请求数据!')
    15. comm_socket.close()
    16. return
    17. recv_content = recv_data.decode('utf-8') # 对二进制数据解码
    18. print('获取到的数据内容为:', recv_content)
    19. request_list = recv_content.split(" ", maxsplit=2) # 根据指定字符串空格进行分割,最大分割次数为2
    20. request_path = request_list[1] # 获取请求资源路径
    21. print('请求路径为:', request_path)
    22. if request_path == "/": # 判断请求的是否是根目录,若是则返回首页指定数据
    23. request_path = "/index.html"
    24. try:
    25. with open('C:/Users/熊世强/Desktop/ubuntu' + request_path, 'rb') as file: # 动态打开指定文件
    26. file_data = file.read() # 读取指定文件数据
    27. except Exception as e: # 请求异常,资源不存在,返回指定404错误数据
    28. with open('C:/Users/熊世强/Desktop/ubuntu/error.html', 'rb') as file: # 打开指定错误文件
    29. error_data = file.read() # 读取指定错误数据
    30. response_line = "HTTP/1.1 404 Not Found!!\r\n" # 响应行
    31. response_header = "Server: PWS1.0 服务器名称及版本……\r\n" # 响应头
    32. response_body = error_data # 响应体
    33. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body # 拼接响应报文
    34. comm_socket.send(response_data) # 发送数据给浏览器
    35. else:
    36. response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
    37. response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
    38. response_body = file_data
    39. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
    40. comm_socket.send(response_data)
    41. finally:
    42. comm_socket.close() # 关闭服务于客户端的套接字
    43. def start(self): # 启动web服务器
    44. while True:
    45. comm_socket, ip_port = self.server_socket.accept() # 等待接收客户端连接请求
    46. thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,)) # 若客户端和服务器建立连接,则创建子线程
    47. thread.setDaemon(True) # 设置守护子线程
    48. thread.start() # 启动子线程执行对应任务
    49. def main(): # 程序入口函数
    50. webServer = HttpWebServer() # 创建web服务器对象
    51. webServer.start() # 启动web服务器进行工作
    52. if __name__ == '__main__':
    53. main()

    输出如下

    1. 获取到的数据内容为: GET /index.html HTTP/1.1
    2. Host: 127.0.0.1:9000
    3. Connection: keep-alive
    4. Cache-Control: max-age=0
    5. sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
    6. sec-ch-ua-mobile: ?0
    7. sec-ch-ua-platform: "Windows"
    8. Upgrade-Insecure-Requests: 1
    9. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
    10. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3;q=0.9
    11. Sec-Fetch-Site: none
    12. Sec-Fetch-Mode: navigate
    13. Sec-Fetch-User: ?1
    14. Sec-Fetch-Dest: document
    15. Accept-Encoding: gzip, deflate, br
    16. Accept-Language: zh-CN,zh;q=0.9
    17. Cookie: csrftoken=1wb7v0r0BQuokJCxRS4JAO2XApvrHXFP90t2PiYb0mz7AwWS0NoKTi0zNaIjOfTl; Hm_lvt_18f619820855042bca58b32408f44de7=1658219884
    18. 请求路径为: /index.html

    浏览器响应如下

     三、静态web服务器-命令行启动动态绑定端口号

    • 实现步骤
      • 获取执行python程序的终端命令行参数
      • 判断参数类型,设置端口号必须是整型
      • 为web服务器类的初始化方法添加一个端口号参数,用于绑定端口号

    实现代码

    1. import socket
    2. import threading
    3. import sys
    4. class HttpWebServer(object): # 定义web服务器类,将提供服务的web服务器抽象为一个类
    5. def __init__(self, port): # 初始化服务端套接字,添加端口号参数
    6. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 创建TCP套接字
    7. server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 设置端口复用,程序退出端口号立即释放
    8. server_socket.bind(("", port)) # 绑定端口号
    9. server_socket.listen(128) # 设置监听
    10. self.server_socket = server_socket
    11. @staticmethod
    12. def handle_client_request(comm_socket): # 处理客户端请求
    13. recv_data = comm_socket.recv(4096) # 接收请求的二进制数据
    14. if len(recv_data) == 0:
    15. print('未获取到请求数据!')
    16. comm_socket.close()
    17. return
    18. recv_content = recv_data.decode('utf-8') # 对二进制数据解码
    19. print('获取到的数据内容为:', recv_content)
    20. request_list = recv_content.split(" ", maxsplit=2) # 根据指定字符串空格进行分割,最大分割次数为2
    21. request_path = request_list[1] # 获取请求资源路径
    22. print('请求路径为:', request_path)
    23. if request_path == "/": # 判断请求的是否是根目录,若是则返回首页指定数据
    24. request_path = "/index.html"
    25. try:
    26. with open('C:/Users/username/Desktop/ubuntu' + request_path, 'rb') as file: # 动态打开指定文件
    27. file_data = file.read() # 读取指定文件数据
    28. except Exception as e: # 请求异常,资源不存在,返回指定404错误数据
    29. with open('C:/Users/username/Desktop/ubuntu/error.html', 'rb') as file: # 打开指定错误文件
    30. error_data = file.read() # 读取指定错误数据
    31. response_line = "HTTP/1.1 404 Not Found!!\r\n" # 响应行
    32. response_header = "Server: PWS1.0 服务器名称及版本……\r\n" # 响应头
    33. response_body = error_data # 响应体
    34. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body # 拼接响应报文
    35. comm_socket.send(response_data) # 发送数据给浏览器
    36. else:
    37. response_line = "HTTP/1.1 200 OK # 成功!!\r\n"
    38. response_header = "Server: PWS1.0 # 服务器名称版本!\r\n"
    39. response_body = file_data
    40. response_data = (response_line + response_header + '\r\n').encode('utf-8') + response_body
    41. comm_socket.send(response_data)
    42. finally:
    43. comm_socket.close() # 关闭服务于客户端的套接字
    44. def start(self): # 启动web服务器
    45. while True:
    46. comm_socket, ip_port = self.server_socket.accept() # 等待接收客户端连接请求
    47. thread = threading.Thread(target=self.handle_client_request, args=(comm_socket,)) # 若客户端和服务器建立连接,则创建子线程
    48. thread.setDaemon(True) # 设置守护子线程
    49. thread.start() # 启动子线程执行对应任务
    50. def main(): # 程序入口函数
    51. print('命令行输入的参数为:', sys.argv)
    52. if len(sys.argv) != 2: # 判断命令行参数个数是否为2
    53. print("请执行格式为[ python3 xx.py 9000 ] 的命令")
    54. return
    55. if not sys.argv[1].isdigit(): # 判断字符串是否为数字组成,必须为整型
    56. print("请执行格式为[ python3 xx.py 9000 ]的命令")
    57. return
    58. port = int(sys.argv[1]) # 获取终端命令行参数
    59. web_server = HttpWebServer(port)
    60. web_server.start()
    61. if __name__ == '__main__':
    62. main()

    命令行执行

     浏览器响应如下 

     学习导航:http://xqnav.top/

  • 相关阅读:
    大数据定价方法的国内外研究综述及对比分析
    Spring MVC更多家族成员---框架内异常处理与HandlerExceptionResolver---09
    一步一招,教你如何制作出成功的优惠促销微传单
    【论文笔记】policy-space response oracles (PSRO)
    Excel函数公式大全—LOOKUP函数
    数据结构:八种常见数据结构
    【Js】数据处理
    Web 中间件怎么玩?
    有没有人声和背景音乐分离的神器?
    【Java 进阶篇】使用 JDBCTemplate 执行 DQL 语句详解
  • 原文地址:https://blog.csdn.net/qq_43874317/article/details/127439451