HTTPServer v2.0

day12/http_server.py

  1. 主要功能 :
    【1】 接收客户端(浏览器)请求
    【2】 解析客户端发送的请求
    【3】 根据请求组织数据内容
    【4】 将数据内容形成http响应格式返回给浏览器
  2. 升级点 :
    【1】 采用IO并发,可以满足多个客户端同时发起请求情况
    【2】 做基本的请求解析,根据具体请求返回具体内容,同时满足客户端简单的非网页请求情况
【3】 通过类接口形式进行功能封装

技术分析

  1. 使用tcp通信,基于http协议格式
  2. select io多路复用

结构:

采用各类封装

类的接口设计:

  1. 在用户使用的角度进行流程设计
  2. 当需要完成的功能是一个比较大的概括的功能,可以提供继承方法,让别人使用时继承你的类
  3. 针对一个非常具体的功能,尽量帮用户实现更多的功能,让用户尽可能少的修改代码或者尽可能简单的使用
  4. 不能够替用户决定的属性,让用户传参
  5. 不能替用户决定的复杂功能,让用户去重写
  6. 确定功能,参数,使用方法
"""
http_server v2.0
io多路复用 和 http 训练
"""

from socket import *
from select import *


# 具体功能实现
class HTTPServer:
def __init__(self, addr=(('0.0.0.0', 8888)), dir='./static'):
self.addr = addr
self.dir = dir
# 多路复用列表
self.rlist = []
self.wlist = []
self.xlist = []
self.create_socket()
self.bind()

# 创建套接字
def create_socket(self):
self.sockfd = socket()
self.sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 绑定地址
def bind(self):
self.sockfd.bind(self.addr)

# 处理请求
def handle(self, c):
# 接收HTTP请求
request = c.recv(4096)
if not request:
self.rlist.remove(c)
c.close()
return
# 提取请求内容 splitlines将字节串按行分割
request_line = request.splitlines()[0]
print(request_line.decode())
info = request_line.decode().split(' ')[1]
print(c.getpeername(), ':', info)

# 根据请求内容进行数据整理
# 分为两类 1.请求网页 2.其他
if info == '/' or info[-5:] == '.html':
self.get_html(c,info)
else:
self.get_other(c)
# self.rlist.remove(c)

# 返回网页
def get_html(self,c,info):
if info =='/':
# 请求主页
filename = self.dir + '/index.html'
else:
filename = self.dir +info
try:
fd = open(filename,'rb')
except Exception:
# 网页不存在
response = 'HTTP/1.1 404 Not Found\r\n'
response += 'Content-type:text/html\r\n'
response += '\r\n'
response += '<h1>Sorry..页面不存在</h1>\r\n'
response = response.encode()
else:
# 网页存在
response = 'HTTP/1.1 200 OK\r\n'
response += 'Content-type:text/html\r\n'
response += '\r\n'
response = response.encode()
response += fd.read()
finally:
# 将响应放松给浏览器
c.send(response)



# 其他数据
def get_other(self,c):
response = 'HTTP/1.1 200 OK\r\n'
response += 'Content-type:text/html\r\n'
response += '\r\n'
response += '<h1>Waiting for httpserver 3.0</h1>\r\n'
response = response.encode()
c.send(response)



# 启动服务
def serve_forever(self):
self.sockfd.listen(3)
print('Listen the port %d' % self.addr[1])
# IO多路复用接收客户端请求
self.rlist.append(self.sockfd)
while True:
rs, ws, xs = select(self.rlist, self.wlist, self.xlist)
for r in rs:
if r is self.sockfd:
c, addr = r.accept()
# print('Connect from', addr)
self.rlist.append(c)
else:
self.handle(r)


# 用户使用HTTPServer
if __name__ == '__main__':
"""
通过 HTTPServer 类快速搭建服务,展示自己的网页
"""
# 用户决定的参数
HOST = '0.0.0.0'
PORT = 38383
ADDR = ((HOST, PORT))
# 网页存储位置
DIR = 'static'
# 实例化对象
httpd = HTTPServer(ADDR, DIR)
# 启动服务
httpd.serve_forever()