06 | python HTTPServer(入门)
目标:理解 httpserver 开发的流程 ,为后面学习成熟的框架打好基础。理解配置文件这种与用户交互的方式。理解 httpserver 和 webframe 两部分的作用。 复习 多线程并发 和 IO 多路复用。理解 功能类的封装。理解 网站请求有 页面和数据两类。
功能 :
httpserver部分
获取http请求
解析http请求
将请求发送给WebFrame
从WebFrame接收反馈数据
将数据组织为Response格式发送给客户端
WebFrame部分
从httpserver接收具体请求
根据请求进行逻辑处理和数据处理
将需要的数据反馈给httpserver
特点
采用httpserver和应用处理分离的模式,降低了耦合度
采用了用户配置文件的思路
webframe部分采用了模拟后端框架的处理方法
技术点
httpserver部分需要与两端建立通信
webFrame部分采用多路复用接收并发请求
数据传递使用json格式
项目结构:
|--httpserver --HttpServer.py (主程序) | --config (httpserver配置) project--| | | |--WebFrame --WebFrame.py (主程序代码) --static (存放静态网页) --views.py ( 应用处理程序) --urls.py (存放路由) --settings (框架配置)
交互数据格式协议
httpserver-->webframe {method:'GET',info:'/'} webframe-->httpserver {status:'200',data:'ccccc'}
🔧HTTPserver代码
""" config.py http server 相关配置 需要使用者提供的内容写在配置文件 """ # [http server address] HOST = '0.0.0.0' PORT = 8000 # [debug] DEBUG = True # web frame地址 frame_ip = '127.0.0.1' frame_port = 8080
""" httpserver.py httpserver 3.0 获取http请求 解析http请求 将请求发送给WebFrame 从WebFrame接收反馈数据 将数据组织为Response格式发送给客户端 """ from socket import * import sys from threading import Thread import json,re from config import * # 导入配置文件内容 # 负责和webframe交互, socket客户端 def connect_frame(env): s = socket() try: s.connect((frame_ip,frame_port)) except Exception as e: print(e) return # 将env转换为json发送 data = json.dumps(env) s.send(data.encode()) # 接收webframe反馈的数据 data = s.recv(1024 * 1024 * 10).decode() return json.loads(data) # httpserver功能 class HTTPServer: def __init__(self): self.host = HOST self.port = PORT self.create_socket() self.bind() # 创建套接字 def create_socket(self): self.sockfd = socket() self.sockfd.setsockopt(SOL_SOCKET, # 是否端口立即重用 SO_REUSEADDR, DEBUG) # 绑定地址 def bind(self): self.address = (self.host,self.port) self.sockfd.bind(self.address) # 启动服务 def serve_forever(self): self.sockfd.listen(5) print("Start the http server:%d"%self.port) while True: connfd,addr = self.sockfd.accept() client = Thread(target=self.handle, args=(connfd,)) client.setDaemon(True) client.start() # 具体处理客户端请求 def handle(self,connfd): request = connfd.recv(4096).decode() pattern=r'(?P<method>[A-Z]+)\s+(?P<info>/\S*)' try: env = re.match(pattern,request).groupdict() # match 是从开头开始匹配防止后面也有类似内容 except: connfd.close() return else: # data就是从webframe得到的数据 data = connect_frame(env) if data: self.response(connfd,data) def response(self,connfd,data): # data-->{'status':'200','data':'xxx'} if data['status'] == '200': responseHeaders = "HTTP/1.1 200 OK\r\n" responseHeaders += 'Content-Type:text/html\r\n' responseHeaders += '\r\n' responseBody = data['data'] elif data['status'] == '404': responseHeaders = "HTTP/1.1 404 Not Found\r\n" responseHeaders += 'Content-Type:text/html\r\n' responseHeaders += '\r\n' responseBody = data['data'] elif data['status'] == '302': pass # 将数据发送给浏览器 data = responseHeaders+responseBody connfd.send(data.encode()) if __name__ == '__main__': httpd = HTTPServer() httpd.serve_forever() # 启动服务
#server_test.py # 用户测试httpserver from socket import * import json s = socket() s.bind(('127.0.0.1',8080)) s.listen(5) while True: c,addr = s.accept() data = c.recv(1024) print(data) data = json.dumps({'status':'200','data':'ccccccc'}) c.send(data.encode())
🔧webframe 代码
""" settings.py web frame 部分的配置文件 """ # [frame address] frame_ip = '127.0.0.1' frame_port = 8080 # [debug] DEBUG = True # [static] STATIC_DIR = "./static"
""" url.py 声明客户端能够请求的数据 """ from views import * urls = [ ('/time',show_time), ('/guonei',guonei), ('/guoji',guoji) ]
""" views.py 数据处理的具体函数 """ import time def show_time(): return time.ctime() def guonei(): return "你看到了国内新闻" def guoji(): return "你看到了国际新闻"
""" webframe.py 模拟网站的后端应用 从httpserver接收具体请求 根据请求获取网页 将需要的数据反馈给httpserver """ from socket import * import json from settings import * from select import * from urls import * # 应用类,实现具体的后端功能 class Application: def __init__(self): self.host = frame_ip self.port = frame_port self.fdmap = {} # 查找地图 self.ep = epoll() # epoll对象 self.sockfd = socket() self.sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, DEBUG) self.sockfd.bind((self.host,self.port)) # 用于服务启动 def start(self): self.sockfd.listen(5) print("Listen the port %d"%self.port) # 关注sockfd self.ep.register(self.sockfd,EPOLLIN) self.fdmap[self.sockfd.fileno()] = self.sockfd while True: events = self.ep.poll() for fd,event in events: if fd == self.sockfd.fileno(): connfd,addr = self.fdmap[fd].accept() self.ep.register(connfd) self.fdmap[connfd.fileno()] = connfd else: self.handle(self.fdmap[fd]) self.ep.unregister(fd) del self.fdmap[fd] # 具体处理请求 def handle(self,connfd): request = connfd.recv(1024).decode() request = json.loads(request) # request -> {'method':'GET','info':'/'} if request['method'] == 'GET': if request['info'] == '/' or \ request['info'][-5:] == '.html': response = self.get_html(request['info']) else: response = self.get_data(request['info']) elif request['method'] == 'POST': pass # 将数据发送给HTTPserver response = json.dumps(response) connfd.send(response.encode()) connfd.close() # 网页处理函数 def get_html(self,info): if info == '/': filename = STATIC_DIR+'/index.html' else: filename = STATIC_DIR+info try: fd = open(filename) except: f = open(STATIC_DIR+'/404.html') return {'status':'404','data':f.read()} else: return {'status':'200','data':fd.read()} # 处理数据 def get_data(self,info): for url,func in urls: if url == info: return {'status':'200','data':func()} return {'status':'404','data':'Sorry...'} if __name__ == '__main__': app = Application() app.start()
分类:
python
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)