- HTTP 请求报文格式:
Host: 127.0.0.1:8888
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
- HTTP 响应报文格式:
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 14 Mar 2018 09:52:48 GMT
Server: BWS/1.1
采用 TCP 协议创建 socket 套接字对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 复用端口
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定 IP 和端口
server_socket.bind(('', 8888))
# 开启监听,由主动模式变为被动模式
server_socket.listen()
等待客户端的连接,并接收客户端请求数据
# 等待客户端连接
new_socket, client_addr = server_socket.accept()
# 接收浏览器发送的请求
recv_data = new_socket.recv(1024).decode()
# 防止客户端下线导致bug
if not recv_data:
print("客户端下线!")
new_socket.close()
continue
解析请求并返回数据
# 从请求行获取路径信息
data_list = recv_data.splitlines()
request_line = data_list[0]
regex = re.match(r'.* (.*) .*', request_line)
file_path = regex.group(1)
if file_path == '/':
file_path = '/myWeChat.html'
try:
# 采用二进制读取本地文件内容(方便读取图片等非文本文件)
with open(f'.{file_path}', 'rb') as f:
response_body = f.read()
except Exception as reason:
# 没有相关文件资源时返回 404 错误
response_line = "HTTP/1.1 404 Not Found\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
response_body = f'<h2>404 {reason}</h2>'.encode()
else:
# 解析请求
response_line = "HTTP/1.1 200 OK\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
finally:
# 响应请求并返回数据
response = response_line + response_headers
new_socket.send(response.encode() + response_body)
# 关闭
new_socket.close()
# 从请求行获取路径信息
data_list = recv_data.splitlines()
request_line = data_list[0]
regex = re.match(r'.* (.*) .*', request_line)
file_path = regex.group(1)
该代码可以显示指定页面
if file_path == '/':
file_path = '/myWeChat.html'
该代码可以设置默认首页
完整代码:
import re
import socket
if __name__ == '__main__':
"""返回固定的页面数据"""
# 采用 TCP 协议创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 使端口重复使用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定 IP 和端口
server_socket.bind(('', 8888))
# 开启监听,由主动模式变为被动模式
server_socket.listen()
while True:
# 等待客户端连接
new_socket, client_addr = server_socket.accept()
# 接收浏览器发送的请求
recv_data = new_socket.recv(1024).decode()
# 防止客户端下线导致bug
if not recv_data:
print("客户端下线!")
new_socket.close()
continue
# 从请求行获取路径信息
data_list = recv_data.splitlines()
request_line = data_list[0]
regex = re.match(r'.* (.*) .*', request_line)
file_path = regex.group(1)
if file_path == '/':
file_path = '/myWeChat.html'
try:
# 采用二进制读取本地文件内容(方便读取图片等非文本文件)
with open(f'.{file_path}', 'rb') as f:
response_body = f.read()
except Exception as reason:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
response_body = f'<h2>404 {reason}</h2>'.encode()
else:
# 解析请求
response_line = "HTTP/1.1 200 OK\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
finally:
# 响应请求并返回数据
response = response_line + response_headers
new_socket.send(response.encode() + response_body)
# 关闭
new_socket.close()
一个 web 服务器开发完了。等等,这个服务器好像有点问题,当一个客户端连接时其他客户端就没法连接了。我开发服务器并不是为一个人服务,开发服务器也要符合社会主义核心价值观,要为人民服务。
通过多协程实现多用户处理
import re
import socket
from gevent import monkey
import gevent
# 可以简单理解为将一些模块变为非阻塞,具体解释需要上网查阅资料
monkey.patch_all()
def handle_request(new_socket):
# 接收浏览器发送的请求
recv_data = new_socket.recv(1024).decode()
# 防止客户端下线导致bug
if not recv_data:
print("客户端下线!")
new_socket.close()
return
# 从请求行获取路径信息
data_list = recv_data.splitlines()
request_line = data_list[0]
regex = re.match(r'.* (.*) .*', request_line)
file_path = regex.group(1)
if file_path == '/':
file_path = '/myWeChat.html'
try:
# 采用二进制读取本地文件内容(方便读取图片等非文本文件)
with open(f'.{file_path}', 'rb') as f:
response_body = f.read()
except Exception as reason:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
response_body = f'<h2>404 {reason}</h2>'.encode()
else:
# 解析请求
response_line = "HTTP/1.1 200 OK\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
finally:
# 响应请求并返回数据
response = response_line + response_headers
new_socket.send(response.encode() + response_body)
# 关闭
new_socket.close()
def main():
"""程序主入口,实现 web 服务器功能"""
# 采用 TCP 协议创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 使端口重复使用
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定 IP 和端口
server_socket.bind(('', 8888))
# 开启监听,由主动模式变为被动模式
server_socket.listen()
while True:
# 等待客户端连接
new_socket, client_addr = server_socket.accept()
gevent.spawn(handle_request, new_socket)
if __name__ == '__main__':
main()
总感觉还是差了点什么,哦,对了,python 是面向对象语言,这个代码没有对象啊,现实中没有对象,写个代码还没有对象,一万点暴击伤害。下面来个终极版的面向对象封装
import re
import socket
from gevent import monkey
import gevent
monkey.patch_all() # 可以简单理解为使一些模块变为非阻塞,具体原理可以上网查询资料
class WebServer:
def __init__(self):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self.server_socket.bind(('', 8888))
self.server_socket.listen()
def handle_request(self, new_socket):
"""处理请求并完成响应操作"""
# 接收浏览器发送的请求
recv_data = new_socket.recv(1024).decode()
# 防止客户端下线导致bug
if not recv_data:
print("客户端下线!")
new_socket.close()
return
# 从请求行获取路径信息
data_list = recv_data.splitlines()
request_line = data_list[0]
regex = re.match(r'.* (.*) .*', request_line)
file_path = regex.group(1)
if file_path == '/':
file_path = '/myWeChat.html'
try:
# 采用二进制读取本地文件内容(方便读取图片等非文本文件)
with open(f'.{file_path}', 'rb') as f:
response_body = f.read()
except Exception as reason:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
response_body = f'<h2>404 {reason}</h2>'.encode()
else:
# 解析请求
response_line = "HTTP/1.1 200 OK\r\n"
response_headers = "Server: WASPVAE/6.6\r\n"
response_headers += "Connection: Keep_Alive\r\n"
response_headers += "Content-Type: text/html;charset=utf-8\r\n" # 解决中文乱码问题
response_headers += "\r\n"
finally:
# 响应请求并返回数据
response = response_line + response_headers
new_socket.send(response.encode() + response_body)
# 关闭
new_socket.close()
def run(self):
"""运行服务器,接收客户端的请求,处理请求并完成响应操作"""
while True:
# 等待客户端连接
new_socket, client_addr = self.server_socket.accept()
gevent.spawn(self.handle_request, new_socket)
def main():
"""程序主入口,实现 web 服务器功能"""
web_server = WebServer()
web_server.run()
if __name__ == '__main__':
main()
可以在项目当前文件夹添加几个 html 文件在浏览器输入 localhost:8888/xxx.html 或者 127.0.0.1:8888/xxx.html测试下
有兴趣的朋友可以关注下我的微信个人订阅号python数据之路,里面有我之前自学 python 的一些资料和在黑马学习的心得与笔记。