HTTP服务器--面向对象
import socket
import gevent
import time
from gevent import monkey
class WebServer(object):
"""把http服务器的功能都封装在WebServer类中"""
DOCUMENTS_ROOT = './html' # 这里配置服务器,配置服务端的文档根路径
def __init__(self):
monkey.patch_all() # 打gevent补丁
# 创建监听套接字
self.http_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 当套接字四次挥手,可立即复用地址端口
self.http_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 服务端绑定端口
self.http_server_socket.bind(('', 7788))
# 开启监听
self.http_server_socket.listen(128)
def __del__(self):
# 关闭监听套接字
self.http_server_socket.close()
def startup(self):
# 等待接受浏览器客户端的请求
while True:
client_socket, client_addr = self.http_server_socket.accept()
# 开启gevent协程处理请求
g1 = gevent.spawn(self.handle_client, client_socket)
g1.join()
def handle_client(self, client_socket):
"""为客户端服务"""
print("当前gevent协程对象:", gevent.getcurrent())
# 接收从客户端发送的数据
recv_data = client_socket.recv(4096)
if not recv_data:
return # 假如服务端没有收到请求数据,直接返回
# 解码
request_data = recv_data.decode("utf-8")
# 按行分离字符串
request_lines = request_data.splitlines()
print("客户端的请求报文数据如下:")
for line in request_lines:
print(line)
# 请求行: GET /index.html HTTP/1.1
request_line = request_lines[0]
# 通过请求行取得请求路径,即要求的页面路径
get_file_name = request_line.split(" ")[1]
print("客户端要求的页面是: ===>%s" % get_file_name)
# 如果没有指定访问哪个页面,默认指定index.html
# GET / HTTP/1.1
if get_file_name == "/":
get_file_name = WebServer.DOCUMENTS_ROOT + "/index.html"
else:
get_file_name = WebServer.DOCUMENTS_ROOT + get_file_name
print("服务端回传的页面是: ===>%s" % get_file_name)
# 按照http 响应报文格式去回复客户端
"""http 响应报文格式
1. 响应行 : HTTP/1.1 200 OK
2. 响应头 Server: mimiweb1.0 Connection: Keep-alive
3. 分隔符 \r\n
4. 响应体 网页的具体内容
"""
try:
f = open(get_file_name, "rb")
except IOError:
"""请求异常"""
# 404表示没有这个页面
response_line = "HTTP/1.1 404 Not Found\r\n" # 响应行,必写
response_headers = "Server: mimiweb1.0\r\n" # 设置响应头
split = "\r\n" # 分割线
response_body = "====sorry ,file not found====" # 设置响应体
response_body = response_body.encode('utf-8') # 注意,一定要重新赋值,否则response_body还是字符串,而不是字节串
else:
"""请求成功"""
response_line = "HTTP/1.1 200 OK\r\n" # 响应行,必写
response_headers = "Server: mimiweb1.0\r\n" # 设置响应头
split = "\r\n" # 分割线
# 设置响应体
response_body = f.read()
f.close()
finally:
# 因为头信息在组织的时候,是按照字符串组织的,不能与以二进制打开文件读取的数据合并,因此分开发送
# 先发送response的头信息
client_socket.send((response_line + response_headers + split).encode('utf-8'))
# 再发送body
client_socket.send(response_body)
# 关闭套接字
client_socket.close()
def main():
"""程序主控制入口"""
web_server = WebServer()
web_server.startup()
if __name__ == '__main__':
main()