获取http请求
解析http请求
将请求发送给WebFrame
从WebFrame接收反馈数据
将数据组织为Response格式发送给客户端
从httpserver接收具体请求
根据请求进行逻辑处理和数据处理
将需要的数据反馈给httpserver
dict_={"name":"梅梅","age":20,"height":168,"gender":"女"}
# 打包:python数据---> json,支持转换python数据格式:dict,list
jdata=json.dumps(dict_)
# 解析:json格式数据---> python
py_data=json.loads(jdata)
re=r"[A-Z]+\s+\S*"
re=r"(?P[A-Z]+)\s+(?P\S*)"
方案 | 实现方法 |
---|---|
多进程 | os模块fork()实现多进程: multiprocessing模块Process实现多进程: 1.为单独的入口函数开辟单独进程 2.自定义进程类,run定义启动函数,可以将共同使用的数据封装为类实例变量 |
多线程 | multiprocessing模块Tread实现多进程: 1.与Process进程模块使用方法相同 2.注意区别python线程和进程的区别 |
IO多路复用 | IO多路复用适合处理IO请求密集型问题,对于长期占用服务处理逻辑需要用多进程/线程 select–rs,ws,xs=select(rlist,wlist,xlist) rlist监听读属性IO,连接结束删除监听对象 poll—fdmap存放文件描述符与IO对象字典,register添加监听对象 epoll-- 与poll使用方法相同,但内部实现机制不同,epoll效率最高,可设置边缘触发 |
httpserver–多线程
webframe–IO多路复用epoll
httpserver-->webframe {method:'GET',info:'/'}
webframe-->httpserver {status:'200',data:'ccccc'}
基本功能 | 函数 | 数据交互方向 | 数据格式 |
---|---|---|---|
1.获取http请求 | handle() | server<–client | http请求 |
2.解析http请求 | handle() | server | http–>json |
3.将请求发送给WebFrame | connect_webframe() | server–>webframe | json |
4.从WebFrame接收反馈数据 | connect_webframe() | server<–webframe | json |
5.将数据组织为响应格式发送客户端 | response() | server–>client | http响应 |
"""
HttpServer
"""
from server.config import *
# httpserver功能
class HTTPServer():
#初始化变量,并调用套接字创建和绑定程序
# 创建套接字
def create_socket(self):
# 套接字地址绑定
def bind(self):
# 启动服务,循环接收网页连接,并分配子线程处理
def server_forever(self):
# 线程主处理函数
def handle(self, connfd):
# 组织对网页请求的具体响应内容
def response(self, connfd, data):
# 链接后端,并将来自浏览器的请求转发给后端,接受后端发送的内容
def connect_webframe(req):
if __name__ == "__main__":
httpd = HTTPServer()
httpd.server_forever()
"""
httpserver相关配置 需要使用者进行配置
"""
# [httpserver address]
HOST="0.0.0.0"
PORT=8000
# [Debug]
DEBUG=1
# [webframe address]
frame_ip="127.0.0.1"
frame_port=8080
"""
从httpserver接收具体请求
根据请求进行逻辑处理和数据处理
将需要的数据反馈给httpserver
"""
from setting import *
from urls import *
# 应用类实现具体应用功能
class Application():
#基本变量初始化
def __init__(self):
# 创建监听套接字
def create_socket(self):
# 绑定地址
def bind(self):
# 初始化epoll文件符-->IO对象映射地图
def init_epoll(self):
# 服务启动(IO多路复用,epoll())
def start(self):
# 逻辑处理请求,发送请求内容
def handle(self,connfd):
# 获取响应内容(网页)
def get_html(self,info):
#获取响应数据(其他类型)
def get_data(self,info):
if __name__=="__main__":
app=Application()
app.start()
# 后端套接字地址
# [webframe address]
frame_host="0.0.0.0"
frame_port=8080
# [Debug]
DEBUG=1
# [static html]
STATIC_DIR="/home/tarena/leixing/code_of_all/projects/http3d0/frame/static"
404.html
index.html
from views import *
urls={
# 非网页请求,请求与函数映射关系
"/time":times,
"/guonei":guonei,
"/guowai":guowai
}
from time import *
# 非网页请求函数实现
def times():
return ctime()
def guonei():
return "guo nei news:hao hao hao!"
def guowai():
return "guo wai news:can can can!"
from socket import *
import os, sys
from threading import Thread
import json
from projects.http3d0.server.config import *
import re
# httpserver功能
class HTTPServer():
#初始化变量,并调用套接字创建和绑定程序
def __init__(self):
self.host = HOST
self.port = PORT
self.create_socket()
self.bind()
# 创建套接字
def create_socket(self):
self.socketfd = socket()
self.socketfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, DEBUG)
# 套接字地址绑定
def bind(self):
self.address = (self.host, self.port)
self.socketfd.bind(self.address)
# 启动服务,循环接收网页连接,并分配子线程处理
def server_forever(self):
self.socketfd.listen(5)
print("Start httpserver:%d" % self.port)
while True:
connfd, addr = self.socketfd.accept()
client = Thread(target=self.handle, args=(connfd,))
client.setDaemon(True)
client.start()
# 线程主处理函数
def handle(self, connfd):
# 接受网页请求
request = connfd.recv(1024).decode()
# 解析请求正则表达式
pattern = r"(?P[A-Z]+)\s+(?P/\S*)"
try:
# {'method': 'GET', 'info': '/'} <--- GET / HTTP/1.1
env = re.match(pattern, request).groupdict()
except:
connfd.close()
return
else:
# data是从webframe返回的请求内容数据
data = connect_webframe(env)
data = json.loads(data)
self.response(connfd, data)
# 组织对网页请求的具体响应内容
def response(self, connfd, data):
# data-->{'sattus':'200','data':'XXX'}
print(data)
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 NotFound\r\n"
responseHeaders += "Content-Type:text/html\r\n"
responseHeaders += "\r\n"
responseBody = data['data']
response = responseHeaders + responseBody
print("RES:", response)
connfd.send(response.encode())
# 链接后端,并将来自浏览器的请求转发给后端,接受后端发送的内容
def connect_webframe(req):
s = socket()
try:
s.connect((frame_ip, frame_port))
except Exception as e:
print(e)
return
# 将内容转化为json,并发送给后端
data = json.dumps(req)
s.send(data.encode())
# 接收webframe发送的内容
wfdata = s.recv(10 * 1024 * 1024).decode()
return wfdata
if __name__ == "__main__":
httpd = HTTPServer()
httpd.server_forever()
from socket import *
import json
from setting import *
import os,sys
from select import *
from urls import *
# 应用类实现具体应用功能
class Application():
#基本变量初始化
def __init__(self):
self.host = frame_host
self.port = frame_port
self.create_socket()
self.bind()
self.init_epoll()
# 创建监听套接字
def create_socket(self):
self.appfd=socket()
self.appfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,DEBUG)
# 绑定地址
def bind(self):
self.ADDR=(self.host,self.port)
self.appfd.bind(self.ADDR)
self.appfd.listen(5)
print("Listen from port:%d"%self.port)
# 初始化epoll文件符-->IO对象映射地图
def init_epoll(self):
self.fdmap={}
self.ep=epoll()
# 关注套接字,并添加文件描述符(每个IO对象唯一)map
# 关注对象和文件符字典始终统一
self.ep.register(self.appfd,EPOLLIN)
self.fdmap[self.appfd.fileno()]=self.appfd
# 服务启动(IO多路复用,epoll())
def start(self):
while True:
events=self.ep.poll()
for fileno,event in events:
if fileno==self.appfd.fileno():
connfd,addr=self.fdmap[fileno].accept()
self.ep.register(connfd)
self.fdmap[connfd.fileno()]=connfd
else:
self.handle(self.fdmap[fileno])
# 取消关注,删除地图对应
self.ep.unregister(fileno)
del self.fdmap[fileno]
# 逻辑处理请求,发送请求内容
def handle(self,connfd):
request=connfd.recv(2048).decode()
request=json.loads(request)
print(request)
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
# 网页转化为json格式并发送给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 in urls:
if info==url:
return {"status": "200", "data": urls[info]()}
return {"status":"404","data":"Request out of range,Only for adults"}
if __name__=="__main__":
app=Application()
app.start()