1. 使用web底层socket的方式实现简易服务器的搭建,用来理解学习
# 1、导入socket模块 import socket import re import gevent import sys # 破解,让gevent 识别耗时操作 from gevent import monkey monkey.patch_all() import Application class HttpServer(object): # 用来初始化 套接字 def __init__(self, port): # 2、创建tcp套接字 tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 3、设置地址重用 tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 4、绑定端口 tcp_server_socket.bind(("", port)) # 5、设置监听,最大允许客户端连接数128(套接字有主动变为被动) tcp_server_socket.listen(128) # 套接字,保存实例属性中 self.tcp_server_socket = tcp_server_socket # 启动Web服务器,并且接受客户端连接 def start(self): # 6、等待客户端连接(能够接受多个客户端连接) while True: # 7、定义函数,实现客户端信息接收和响应 new_client_socket, ip_port = self.tcp_server_socket.accept() print("[新客户端来了]:", ip_port) # request_handler(new_client_socket) g1 = gevent.spawn(self.request_handler, new_client_socket) # 因为接收客户端链接使用的是While True 死循环,主线程不会退出,协程一定会执行完毕 # g1.join() def request_handler(self, new_client_socket): # 8、接收浏览器请求,并判断请求是否为空 recv_data = new_client_socket.recv(1024) if not recv_data: print("浏览器可能已经关闭!~") new_client_socket.close() return # 把接受的内容解码 request_text = recv_data.decode() # 根据 拆分字符串,目的:得到第一行 request_list = request_text.split(" ") # request_list[0] 就是我们的请求行 # print(request_list[0]) ret = re.search(r"s(.*)s", request_list[0]) # 判断报文是否有误 if not ret: print("浏览器请求的报文格式错误!") new_client_socket.close() return # 获取路径 path_info = ret.group(1) # print(path_info) # 访问默认的页面 if path_info == "/": path_info = "/index.html" # 9、拼接响应报文 # 判断如果是动态资源 交给框架处理 if path_info.endswith(".html"): # 字典存储 用户的请求信息 env = { "PATH_INFO": path_info } status, headers, response_body = Application.app(env) # 使用框架返回的数据拼接响应报文 response_line = "HTTP/1.1 %s " % status response_header = "" for header in headers: response_header += "%s: %s " % header response_data = response_line + response_header + " " + response_body new_client_socket.send(response_data.encode()) new_client_socket.close() # 否则认为是静态资源 else: # 9.2 响应头 response_header = "Server:PythonWS1.0 " # 9.3 空行 response_blank = " " # 9.4 响应体 # response_content = "HelloWorld! " # 打开文件,并且读取内容,然后把读取的内容返回给客户端 try: with open("static"+path_info, "rb") as file: # response_content 是二进制类型 response_content = file.read() except Exception as e: # 9.1 相应行 response_line = "HTTP/1.1 404 Not Found " response_content = "Error ! %s" % str(e) # 对返回的内容进行编码 response_content = response_content.encode() else: # 9.1 相应行 response_line = "HTTP/1.1 200 OK " finally: # 10、定义变量保存响应报文内容 response_data = (response_line + response_header + response_blank).encode() + response_content # 11、发送响应报文给客户端浏览器 new_client_socket.send(response_data) # 12、关闭此次连接的套接字 new_client_socket.close() def main(): # sys.argv 可以获取终端启动程序的时候的启动参数 # sys.argv 返回一个列表,列表中依次保存我们输入的参数内容 # print(sys.argv) if len(sys.argv) != 2: print("服务器启动失败,参数的格式:python3 HttpServer.py 端口号") return # 判断端口号,不能是一个字符串,应该是纯数字 if not sys.argv[1].isdigit(): print("服务器启动失败,端口号应该是纯数字!") return # 获取端口号 port = int(sys.argv[1]) # 实例化 HttpServer 对象 httpserver = HttpServer(port) # 启动服务器 httpserver.start() if __name__ == '__main__': main() 2. 建立子应用app用来接收请求 """web框架 web应用程序""" import time def get_time(): """当用户请求/gettime.html执行当前方法""" return time.ctime() def index(): """当用户请求/index.html 执行""" # 1 读取模板文件 with open("template/index.html") as file: html_data = file.read() # 2 查询数据库 data_from_mysql = "have fun" # 3 使用从数据库中查询出来的数据 替换 模板变量 html_data = html_data.replace("{%content%}", data_from_mysql) return html_data def center(): """当用户请求/center.html 执行""" # 1 读取模板文件 with open("template/center.html") as file: html_data = file.read() # 2 查询数据库 data_from_mysql = "have fun" # 3 使用从数据库中查询出来的数据 替换 模板变量 html_data = html_data.replace("{%content%}", data_from_mysql) return html_data # 路由列表 django框架添加路由的方式 route_list = [ ('/gettime.html', get_time), ('/center.html', center), ('/index.html', index) ] def app(env): # 接收 取出用户的信息 path_info = env['PATH_INFO'] print("接收到用户的动态资源请求 %s" % path_info) # if path_info == '/gettime.html': # # 状态 响应头 响应体 # return '200 OK', [('Server', 'PWS5.0')], get_time() # elif path_info == '/index.html': # return '200 OK', [('Server', 'PWS5.0')], index() # elif path_info == '/center.html': # return '200 OK', [('Server', 'PWS5.0')], center() # 将用户请求路径 和 路由列表中每一个进行比较 如果一致 就执行对应的函数代码 for path, func in route_list: if path_info == path: return '200 OK', [('Server', 'PWS5.0')], func() else: # 状态 响应头 响应体 return '404 Not Found',[('Server', 'PWS5.0')],"response body from app"