接上篇
HTTP协议 HTTP请求报文说明 HTTP 响应报文说明 模仿浏览器请求web服务器 web 服务器
web 服务器多任务版
# web 服务器 = TCP 服务器 + HTTP 协议
import socket
import threading
import time
def client_request(new_client_socket, client_address):
# 2. 接受用户请求报文 < 一个套接字如果没有收数据就关了 那么可能报错 >
recv_data = new_client_socket.recv(4096)
# 2.1 判断用户是否已经下线
if not recv_data:
print("客户端%s 已经下线" % str(client_address))
new_client_socket.close()
return
# 2.2 获取到用于请求报文中的资源路径
path_info = recv_data.decode().split(" ")[1]
print("收到用户的自愿请求路径是,", path_info)
#2.3 判断如果用户请求路径是
if path_info =="/":
path_info = "/grand.html"
# 2.4 打开一个指定的文件 读取
try:
# 可能发生异常的代码
with open("./static/" + path_info, "rb") as file:
file_data = file.read()
except Exception as e:
# 如果发生异常执行这
with open("./static/404.html", "rb") as file:
file_data = file.read()
http_response_data = "HTTP/1.1 404 Not Found\r\nServer: PWS1.0 \r\n\r\n".encode() + file_data
else:
# 没有异常执行这里
# 3. 回复响应报文<HTTP 响应报文>
http_response_data = "HTTP/1.1 200 OK\r\nServer" PWS1.0\r\n\r\n".encode() + file_data
finally:
# 不管有没有异常 都执行这里
new_Client_sockt.send(http_response_data)
time.sleep(2)
# 4. 关闭和客户端关联的套接字
new_client_socket.close()
def main():
# 1. 创建一个服务器套接字 绑定 监听转接用户连接请求到和客户端关联的套接字
server_socket = socket.socket()
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 9999))
server_socket.listen(128)
while True:
new_client_socket, client_address = server_socket.accept()
print("客户端%s上线了" % str(client_address))
# 没当有提个用户连接到服务器 启动一个线程或者协程运行对应的代码
thd = threading.Thread(target=client_request, agrs=(new_client_socket, client_address))
thd.daemon = True
thd.start()
if __name__ == "__main__":
main()
面向对象版 web服务器
import socket
import threading
import time
class HTTPServer(objict):
def __init__(self):
"""初始化操作 创建属性"""
# 1. 创建一个服务器套接字 绑定监听用户连接请求到和客户端关联的套接字
server_socket = socket.socket()
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 9999))
server_socket.listen(128)
self.server_socket = server_socket
def start(self):
"""启动 web 服务器的工作"""
while True:
new_client_socket, client_address = self.server_socket.accept()
print("客户端%s 上线了" % str(client_address))
# 每当有一个用户连接到服务器 启动一个线程或者协程运行对应的代码
thd = threading.Thread(target=self.client_request, args=(new_client_socket, client_address))
thd.daemon = True
thd.start()
@staticmethod
def client_request(new_client_socket, client_address):
# 2.接受用户请求报文
recv_data = new_client_socket.recv(4096)
# 2.1 判断用户是否已经下线
if not recv_data:
print("客户端%s 已经下线了" % str(client_address))
new_client_socket.close()
return
# 2.2 获取到用户请求报文中的资源路径
path_info = recv_data.decode().spilt(" ")[1]
print("收到用户的资源请求路径是, " path_info)
# 2.3 判断如果用户请求路径是/
if path_info == "/":
path_info = "/grand.html"
# 2.4 打开一个制定的文件 读取
try:
# 可能发生异常的代码
with open("./static/index.html", "rb") as file:
file_data = file.read()
except Exception as e:
# 如果发生异常 执行这里
with open("/static/404.html", "rb") as file:
file_data = file.read()
http_response_data = "HTTP/1.1 404 NOT Found\r\nServer: PWS1.0\r\n\r\n".encode() + file_data()
else:
# 没有异常执行这里
# 3. 回复响应报文
http_respon_data = "HTTP/1.1 200 OK\r\nServer: PWS1.0\r\n\r\n".encode() + file_data
finally:
# 不管有没有异常 都执行这里
new_client_socket.send(http_response_data)
time.sleep(2)
# 4. 关闭和客户端关联的套接字
new_client_socket.close()
def main():
# 调用类创建一个对象
http_server = HTTPServer() # __init__(self)
http_server.start()
# 实例方法self; 类方法 cls @classmethod ; 静态方法@staticmethod
if __name__ == "__main__":
main()
# 面向对象< 以类和对象方式考虑问题 适用性更高 抽闲能力更好> eg. 人.吃(饭)
# 面向过程(动作功能) eg. 吃(人,饭)
命令行参数指定 web 服务器端口
import socket
import threading
import time
import sys
class HTTPServer(object):
def __init__(self, port):
"""初始化操作 创建属性"""
# 1. 创建一个服务器套接字 绑定监听转接用户连接请求到和客户端关联的套接字
server_socket = socket.socket()
server_socket.setsockopt(socket.SOL)SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", port))
server_socket.listen(128)
self.server_socket = server_socket
def start(self):
""" 启动 web 服务器 """
while True:
new_client-socket, client_address = self.server_socket.accept()
print("客户端%s 上线了" % str(client_address))
# 每当有一个用户连接到服务器 启动一个线程护着协程运行对应的代码
thd = threading.Thread(target=self.client_requset, args=(new_client_socket, client_address))
thd.daemon = True
thd.start
@staticmethod
def client_request(new_client_socket, client_address):
# 2. 接受用户请求报文
recv_data = new_client_socket.recv(4096)
# 2.1 判断用户是否已经下线
if not recv_data:
print("客户端%s 下线了" %s str(client_address))
new_client_socket.close()
return
# 2.2 获取盗用户请求报文中的资源路径
path_info = recv_data.decode().split(" ")[1]
print("收到用户的资源请求路径是," path_info)
# 2.3 判断如果用户请求资源是/
if path_info == "/":
path_infp = "/grand.html"
# 2.4 打开一个指定的文件 读取
try:
# 可能发生错误的代码
with open("./static" + path_info, 'rb') as file:
file_data = file.read()
except Exception as e:
# 如果发生异常 执行这里
with open("./static/404.html", "rb") as file:
file_data = file.read()
http_response_data = "HTTP/1.1 404 Not Found\r\nServer: PWS1.0\r\n\r\n".encode() + file_data
else:
# 没有发生异常执行这
# 3. 回复响应报文
http_response_data = "HTTP/1.1 200 OK\r\nServer: PWS1.0\r\n\r\n".encode() + file_data
finally:
# 不管有没有异常 都执行这里
new_client_socket.send(http_response_data)
time.sleep(2)
# 4. 关闭和客户端关联的套接字
new_client_socket.close()
def main():
# 获取程序命令行参数列表 每个元素都是字符串
if len(sys.argv) <2: # 判断参数个数
print("你输入的参数有误 python3 web.py 8080")
return
# 判断参数2是否全是由数字组成
if not sys.argv[1].isdigit():
print("你输入的参数有误 python3 web.py 8080")
returrn
port = int(sys.argv[1])
# 调用类创建一个对象
http_server = HTTPServer(port)
http_server.start()
if __name__ == "__main__":
main()