Python简易web静态服务器程序搭建
http.server模块介绍,Python多任务与TCP实现简易静态web服务器程序
Python简易web静态服务器程序搭建
Python自带简易静态web服务器搭建
静态web服务器程序指的是可以根据浏览器的请求报文,在响应报文中返回对应静态文件的程序
静态文件是指数据不需要动态生成的文件。
天气预报网站的数据会实时更新,这种网页就是动态网页。静态web服务器程序为静态网页服务。
http.server模块
http.server
是Python自带的一个模块
在终端中进入想要作为web服务器静态文件集的文件夹,运行
python -m http.server port
就可以快速搭建一个简单的静态web服务器
其中
- -m代表运行模块
- port是端口号
如:
将8000作为静态web服务器程序的端口号
在浏览器中输入http://localhost:8000进入
/
主页。因为没有特别指定页面,所以显示如下
输入http://localhost:8000/welcome.html获取welcome页面。
可以看到响应行中服务器名称为
SimpleHTTP/0.6 Python/3.10.3
.
DIY简易静态web服务器程序搭建
其实静态web服务器程序也仅仅只是一个服务端程序而已。它的功能也是接受客户端程序的数据,并向客户端程序发送数据。它也基于TCP协议。只不过比较特殊的是,静态web服务器程序接受和发送的数据格式已经被HTTP协议规定好了。
浏览器程序发送类似以下格式的请求报文:
POST / HTTP/1.1\r\n (请求行)
Host: www.baidu.com\r\n (请求头信息)
....
\r\n (空行)
username=hello&pass=hello\r\n (请求体)
静态web服务器程序回之以类似以下格式的响应报文:
HTTP/1.1 200 OK\r\n (响应行)
Server: BWS/1.1\r\n (响应头信息)
...
\r\n (空行)
<!DOCTYPE html><html lang=“en”> …</html> (响应体)
普通版
步骤
-
创建静态web服务器程序的套接字并绑定端口号
-
设置监听
-
循环接受浏览器连接请求
-
一旦成功建立连接,创建一个子线程
-
在子线程中接受浏览器发送的请求报文
-
在子线程中分析请求报文并编写对应响应报文
-
在子线程中向浏览器发送响应报文
-
在子线程中断开与浏览器的连接
具体代码
import socket
import threading
def handle(handle_socket: "socket.socket"):
"""与浏览器进行数据通信的子线程"""
# 5.在子线程中接受浏览器发送的请求报文
request_data = handle_socket.recv(4096)
# 6.在子线程中分析请求报文并编写对应响应报文
if len(request_data) == 0:
print("浏览器已断开连接...")
handle_socket.close()
return
request_content = request_data.decode("utf-8")
print(request_content)
# 以\r\n分割各项信息
request_list = request_content.split("\r\n")
# 提取请求的资源路径
request_line = request_list[0]
request_line_list = request_line.split(" ")
request_method, request_path, request_version = request_line_list
# 首页
if request_path == "/":
request_path = "/welcome.html"
# 响应行与响应头信息置空
response_line = response_header = ""
# 根据请求路径准备好响应行和响应体
try:
with open("." + request_path, "rb") as request_file:
response_body = request_file.read()
except (FileExistsError, FileNotFoundError):
response_line += f"{request_version} 404 Not Found\r\n"
with open("./404.html", "rb") as request_file:
response_body = request_file.read()
else:
response_line += f"{request_version} 200 OK\r\n"
finally:
# 准备好响应头信息
response_header += "Server: MyWebServer1.0\r\n"
# 7.在子线程中向浏览器发送响应报文
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
handle_socket.send(response_data)
# 8.在子线程中断开与浏览器的连接
handle_socket.close()
def main():
# 1.创建静态web服务器程序的套接字并绑定端口号
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
server_socket.bind(("localhost", 8888))
# 2.设置监听
server_socket.listen(128)
# 3.循环接受浏览器连接请求
while True:
new_socket, address = server_socket.accept()
print("已连接", address, sep=" from ")
# 4.一旦成功建立连接,创建一个子线程
sub_thread = threading.Thread(target=handle, args=(new_socket,), daemon=True)
sub_thread.start()
if __name__ == "__main__":
main()
面向对象版
对普通版进行抽象即可。
代码
import socket
import threading
class MyWebServer(object):
def __init__(self,port):
"""初始化:创建套接字"""
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(("localhost", port))
self.server_socket.listen(128)
def start(self):
"""启动:建立连接,并开启子线程"""
while True:
new_socket, address = self.server_socket.accept()
print("已连接", address, sep=" from ")
# 4.一旦成功建立连接,创建一个子线程
sub_thread = threading.Thread(target=self.handle, args=(new_socket,), daemon=True)
sub_thread.start()
@staticmethod
def handle(handle_socket):
"""利用子线程收发http格式数据"""
request_data = handle_socket.recv(4096)
if len(request_data) == 0:
print("浏览器已断开连接...")
handle_socket.close()
return
request_content = request_data.decode("utf-8")
print(request_content)
# 以\r\n分割各项信息
request_list = request_content.split("\r\n")
# 提取请求的资源路径
request_line = request_list[0]
request_line_list = request_line.split(" ")
request_method, request_path, request_version = request_line_list
# 首页
if request_path == "/":
request_path = "/welcome.html"
# 响应行与响应头信息置空
response_line = response_header = ""
# 根据请求路径准备好响应行和响应体
try:
with open("." + request_path, "rb") as request_file:
response_body = request_file.read()
except (FileExistsError, FileNotFoundError):
response_line += f"{request_version} 404 Not Found\r\n"
with open("./404.html", "rb") as request_file:
response_body = request_file.read()
else:
response_line += f"{request_version} 200 OK\r\n"
finally:
# 准备好响应头信息
response_header += "Server: MyWebServer1.0\r\n"
# 向浏览器发送响应报文
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
handle_socket.send(response_data)
# 断开与浏览器的连接
handle_socket.close()
def main():
my_web_server=MyWebServer(8888)
my_web_server.start()
if __name__ == "__main__":
main()
命令行版
我们可以在终端中通过命令行执行python文件
命令行参数
python 参数1 参数2 参数3...
python
代表用python解释器进行执行,Linux系统可能需要特意指定python3
- 参数1一般是要执行的python文件名
- 参数2,3…一般是传给要运行的python程序的参数。
如我们的案例需要的:
python MyWebServer.py 8888
在代码中访问
import sys
print(sys.argv)
#["MyWebServer.py","8888"]
- 用到了sys模块的argv变量(argument values),它是一个由运行时实际的命令行参数组成的列表。
代码
为了像Python自带的http.server模块一样可以在命令行中运行,我们对main函数作如下改变:
import sys
...
def main()
#命令行参数个数不对
if len(sys.argv) != 2:
print("执行错误。正确格式为python MyWebServer.py 8888(参数个数应为2...)")
return
# 端口号是否为整数
if not sys.argv[1].isdigit():
print("执行错误。正确格式为python MyWebServer.py 8888(端口号应为整数...)")
return
port=int(sys.argv[1])
my_web_server=MyWebServer(port)
my_web_server.start()
...
效果
不输入请求资源地址,默认进入主页(welcome.html)
输入指定资源路径,进入指定页面(advantages.html)
输入不存在资源路径,进入404页面
更多推荐
所有评论(0)