import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()# 识别等待时间,让协程切换
def client_handler(client_socket):
'''接收客户端链接请求,响应对应的的数据'''
# 接收数据
request_data = client_socket.recv(4096)
# 判断是否接收到数据
if not request_data:
print("客户端已经断开链接")
client_socket.close()
return
# 对接收到的客户端请求数据进行解码
request_str_data = request_data.decode()
#对请求的报文进行分割,分割出一个请求各行数列表
data_list = request_str_data.split("\r\n")
# 拿到请求行数据,请求行数据是列表第0个元素
request_line = data_list[0]
# 通过正则匹配到我们请求的文件路径
result = re.match(r"\w+\s+(\S+)", request_line)
# 判断匹配的请求文件路径是否存在
if not result:
print("请求路径不存在")
client_socket.close()
return
path_info = result.group(1)
print("用户请求信息%s" % str(path_info))
# 设置请求域名默认跳转首页
if path_info == "/":
# 指定首页地址
path_info = "/index.html"
# 响应头
response_header = "Server: PWS1.0\r\n"
try:
# 响应体,打开客户端请求的数据
with open("./html" + path_info, "rb") as file:
file_data = file.read()
except Exception as e:
# 构造请求错误响应报文
response_line = "HTTP/1.1 404 NOT FOUND\r\n"
response_body = "EROOR!!! %s".center(800) %(e)
# 拼接响应报文
response_data = response_line + response_header + "\r\n" + response_body
# 给客户端发送响应报文
client_socket.send(response_data.encode())
else:
# 构造请求成功响应报文
response_line = "HTTP/1.1 200 OK\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()
# 创建主函数,定义套接字
def main():
# 创建套接字,指定IP和数据报类型
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 设置绑定,监听,接收链接
server_socket.bind(("", 4433))
server_socket.listen(128)
# 服务器是面向多客户,循环接收客户端请求链接
while True:
client_socket, client_address = server_socket.accept()
print("服务端接收到来自%s的链接请求" % str(client_address))
# 处理链接请求
# client_handler(client_socket)
# 创建协程实现多任务
g1 = gevent.spawn(client_handler, client_socket)
# 保持主进程存活(阻塞主进程,等待协程g1执行完再退出)
# g1.join()
# 程序入口
if __name__ == '__main__':
main()
面向对象封装上面代码
import socket
import re
import gevent
from gevent import monkey
import sys
monkey.patch_all()# 识别等待时间,让协程切换
class HTTPServer(object):
def __init__(self, port):
"""完成实例对象的初始化操作"""
# 创建套接字,指定IP和数据报类型
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口复用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 设置绑定,监听,接收链接
server_socket.bind(("", 4433))
server_socket.listen(128)
# 套接字对象的引用
self.server_socket = server_socket
# 套接字的链接等待
def start(self):
# 服务器是面向多客户,循环接收客户端请求链接
while True:
client_socket, client_address = self.server_socket.accept()
print("服务端接收到来自%s的链接请求" % str(client_address))
# 处理链接请求
# client_handler(client_socket)
# 创建协程实现多任务
g1 = gevent.spawn(self.client_handler, client_socket)
# 保持主进程存活(阻塞主进程,等待协程g1执行完再退出)
#g1.join()
def client_handler(self, client_socket):
'''接收客户端链接请求,响应对应的的数据'''
# 接收数据
request_data = client_socket.recv(4096)
# 判断是否接收到数据
if not request_data:
print("客户端已经断开链接")
client_socket.close()
return
# 对接收到的客户端请求数据进行解码
request_str_data = request_data.decode()
#对请求的报文进行分割,分割出一个请求各行数列表
data_list = request_str_data.split("\r\n")
# 拿到请求行数据,请求行数据是列表第0个元素
request_line = data_list[0]
# 通过正则匹配到我们请求的文件路径
result = re.match(r"\w+\s+(\S+)", request_line)
# 判断匹配的请求文件路径是否存在
if not result:
print("请求路径不存在")
client_socket.close()
return
path_info = result.group(1)
print("用户请求信息%s" % str(path_info))
# 设置请求域名默认跳转首页
if path_info == "/":
# 指定首页地址
path_info = "/index.html"
# 响应头
response_header = "Server: PWS1.0\r\n"
try:
# 响应体,打开客户端请求的数据
with open("./html" + path_info, "rb") as file:
file_data = file.read()
except Exception as e:
# 构造请求错误响应报文
response_line = "HTTP/1.1 404 NOT FOUND\r\n"
response_body = "EROOR!!! %s".center(800) %(e)
# 拼接响应报文
response_data = response_line + response_header + "\r\n" + response_body
# 给客户端发送响应报文
client_socket.send(response_data.encode())
else:
# 构造请求成功响应报文
response_line = "HTTP/1.1 200 OK\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()
# 创建主函数,定义套接字,设置命令行自定义端口运行
def main():
# 判断输入命令参数是否符合要求
if len(sys.argv) != 2:
print("正确打开方式: python3 运行程序.py 端口号")
return
if not sys.argv[1].isdigit():
print("正确打开方式: python3 运行程序.py 端口号")
return
port = int(sys.argv[1])
http_server = HTTPServer(port)
http_server.start()
# 程序入口
if __name__ == '__main__':
main()