1 statichttpserver.py
采用[Python网络编程之TCP]章节中多路复用selector的做法,创建TcpServer。 这里需要注意的是每个请求发送给服务器都建立一条tcp连接,服务器处理完成该请求之后,即断开连接。
# -*- coding: utf-8 -*-
# @Author : 江河
# @Email : 2516638426@qq.com
# @Time : 2020/4/22 7:29
# @File : statichttpserver
# @Project: python高级项目
import selectors
import socket
from http_parsed import BaseRequest
class StaticHttpServer(object):
def __init__(self,host,port):
self.selector = selectors.DefaultSelector()
self.sock = socket.socket()
self.address = (host,port)
self.request_queue_size = 5
self.open_socket()
def accept(self,sock,mask):
sel = self.selector
conn,addr = sock.accept() # Should be ready
conn.setblocking(False)
sel.register(conn,selectors.EVENT_READ,self.read)
def write(self,sock,mask):
print('write')
sel = self.selector
# 组织相应的头信息(header)
response_headers = "HTTP/1.1 200 OK\r\n" # 200表示找到这个资源
response_headers += "\r\n" # 用一个空的行与body进行隔开
# 组织 内容(body)
response_body = "Hello World"
response = response = response_headers + response_body
sock.send(response.encode("utf-8"))
self.unregister(sock)
sock.close()
def read(self,conn,mask):
sel = self.selector
data = conn.recv(1000) # should be ready
if data:
conn.setblocking(False)
sel.unregister(conn)
# print('echoing',repr(data))
s = data.decode('utf-8')
self.req = BaseRequest(s)
# print(self.req.headers)
print(self.req.url)
print(self.req.method)
sel.register(conn,selectors.EVENT_WRITE,self.write)
else:
print('closing',conn)
sel.unregister(conn)
conn.close()
def server_close(self):
self.sock.close()
self.selector.close()
def server_bind(self):
"""
绑定
:return:
"""
sock = self.sock
sock.bind(self.address)
self.server_address = sock.getsockname()
def server_listen(self):
"""
监听
:return:
"""
self.sock.listen(self.request_queue_size)
def open_socket(self):
sock = self.sock
self.server_bind()
self.server_listen()
sock.setblocking(False)
def server_forever(self):
sock = self.sock
sel = self.selector
sel.register(sock,selectors.EVENT_READ,self.accept)
try:
while True:
events = sel.select()
for key,mask in events:
callback = key.data
callback(key.fileobj,mask)
finally:
print('close')
self.server_close()
if __name__ == '__main__':
host = '127.0.0.1'
port = 5001
print('running http://{}:{}'.format(host.port))
httpd = StaticHttpServer(host,port)
httpd.server_forever()
2 http_parsed.py
BaseRequest类主要用来对客户端发过来的http请求进行封装与解析。
# -*- coding: utf-8 -*-
# @Author : 江河
# @Email : 2516638426@qq.com
# @Time : 2020/4/22 7:42
# @File : http_parsed
# @Project: python高级项目
class BaseRequest(object):
"""
base request class
"""
def __init__(self,request):
self.request = request
# print(request)
self._parsed_request()
def _parsed_request(self):
"""
解析 request
:param request()
:return:
"""
self._parsed_header()
self._parsed_body()
def _parsed_header(self):
"""
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:5001
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://127.0.0.1:5001/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
"""
headers = self.request.split('\r\n\r\n',1)[0].split('\r\n')[1:]
query = {}
for h in headers:
k,v = h.split(':',1)
query[k] = v
self.headers = query
def _parsed_body(self):
"""
解析body
:param request:
:return:
"""
self.body = self.request.split('\r\n\r\n',1)[1]
@property
def method(self):
self._method = self.request.split()[0]
return self._method
@property
def url(self):
self._url = self.request.split()[1]
return self._url
@property
def protocol(self):
self._protocol = self.request.split()[2]
return self._protocol