HTTPServer
参考代码: day19/HTTPServer
功能
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部分配置文件
"""
# [http server address] 被浏览器访问
HOST = '0.0.0.0'
PORT = 8000
# 是否调试模式
DEBUG = True
# [后端应用地址] 表明配合的webframe地址
frame_ip = '127.0.0.1'
frame_port = 8080
"""
httpserver部分主程序
获取http请求
解析http请求
将请求发送给WebFrame
从WebFrame接收反馈数据
将数据组织为Response格式发送给客户端
"""
from socket import *
from threading import Thread
from config import *
import re
import json
# 与后端应用交互
def connect_frame(env):
"""
将请求发送给WebFrame
从WebFrame接收反馈数据
"""
s = socket()
try:
s.connect((frame_ip, frame_port))
except Exception as e:
print(e)
return
# 发送json请求
data = json.dumps(env)
s.send(data.encode())
# 获取返回的数据 (json格式)
data = s.recv(1024 * 1024 * 10).decode()
if data:
try:
result = json.loads(data) # 返回字典
except:
pass
return result
# 主体功能写入类
class HTTPServer:
def __init__(self):
self.address = (HOST, PORT)
self.create_socket()
self.bind()
# 创建套接字
def create_socket(self):
self.sock = socket()
self.sock.setsockopt(SOL_SOCKET,
SO_REUSEADDR,
DEBUG)
# 绑定地址
def bind(self):
# 有些属性可以在调用函数时再生产
self.host = HOST
self.port = PORT
self.sock.bind(self.address)
# 服务启动函数 (多线程并发)
def serve_forever(self):
self.sock.listen(3)
print("Listen the port %d" % self.port)
while True:
connfd, addr = self.sock.accept()
print("Connect from", addr)
t = Thread(target=self.handle,
args=(connfd,))
t.setDaemon(True)
t.start()
# 处理具体的浏览器请求
def handle(self, connfd):
# http请求
request = connfd.recv(4096).decode()
pattern = r"(?P<method>[A-Z]+)\s+(?P<info>/\S*)"
try:
env = re.match(pattern, request).groupdict()
except:
connfd.close()
return
else:
# 与webframe交互 (数据字典/None)
data = connect_frame(env)
if data:
self.response(connfd, data)
# 组织响应格式
def response(self, connfd, data):
# data->{'status':'200','data':'zzzz'}
if data['status'] == '200':
res="HTTP/1.1 200 OK\r\n"
res+="Content-Type:text/html\r\n"
res+="\r\n"
res+=data['data']
elif data['status'] == '404':
res="HTTP/1.1 404 Not Found\r\n"
res+="Content-Type:text/html\r\n"
res+="\r\n"
res+=data['data']
connfd.send(res.encode()) # 响应给浏览器
if __name__ == '__main__':
httpd = HTTPServer()
httpd.serve_forever() # 启动服务```
```python
from socket import *
import json
s = socket()
s.bind(('127.0.0.1',8080))
s.listen(3)
while True:
c,addr = s.accept()
data = c.recv(1024).decode()
print(data)
data = json.dumps({'status':'200','data':'OK'})
c.send(data.encode())```
```python
"""
路由选择模块
"""
from views import *
urls = [
# 如果你访问'/time'这个路径,我有数据,
# 用show_time这个方法给你提供
("/time",show_time),
("/hello",hello),
("/bye",bye),
"""
webframe 配置文件
"""
# [frame address]
frame_ip = '0.0.0.0'
frame_port = 8080
# [debug]
DEBUG = True
# [save html pages]
STATIC_DIR = "./static"
"""
数据处理模块
"""
def show_time():
import time
return time.ctime()
def hello():
return "Hello world"
def bye():
return "good bye"
"""
webframe 模拟网站应用做数据处理
从httpserver接收具体请求
根据请求进行逻辑处理和数据处理
将需要的数据反馈给httpserver
"""
from socket import *
import json
from threading import Thread
from settings import *
from urls import *
# 应用类
class Application:
def __init__(self):
self.host = frame_ip
self.port = frame_port
self.address = (frame_ip, frame_port)
self.sock = socket()
self.sock.setsockopt(SOL_SOCKET,
SO_REUSEADDR,
DEBUG)
self.sock.bind(self.address)
def start(self):
self.sock.listen(3)
print("Running web frame %d" % self.port)
while True:
connfd, addr = self.sock.accept()
print("Connect from", addr)
t = Thread(target=self.handle,
args=(connfd,))
t.setDaemon(True)
t.start()
# 具体处理请求
def handle(self, connfd):
request = connfd.recv(1024).decode()
request = json.loads(request) # 请求字典
# request --> {'method':'GET','info':'XXX'}
# 判定请求类型
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 => {'status':'200','data':'xxx'}
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:
f = open(filename)
except Exception as e:
with open(STATIC_DIR+"/404.html") as fd:
data = fd.read()
return {'status':'404','data':data}
else:
data = f.read()
f.close()
return {'status':'200','data':data}
# 其他处理
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() # 启动应用