描述:
可以用一个小故事来生动描述用户与服务器交互的原理 移动公司式理解
要能办理用户手机业务需求 首先要先开一个移动公司, 有一个总台(socket_server= socket.socket()) 移动公司建立了之后要有自己的专用电话号码(移动是10086, 联通是10010),用户才能知道怎么样能找到我们办理业务(socket_server.bind(('', 8080))), 绑定了自己的专用号码之后就要时时监听着电话,有用户打电话办理业务好及时知道(socket_server.listen(128)), 有用户打进来了总台就要接受用户,让用户打进来,然后就会派一个专门的客服人员负责处理用户的需求(clint_socket,adress= socket_server.accept()) (大家都知道 拨打10086时候 刚开始是总台说话(socket_server)接待自己, 然后自己要办理业务,总台就会分派一个客服人员(clint_socket)为自己办理业务 以后的服务都是客服人员在办理 自己说需求 客服人员办理之后给自己反馈) 然后客服人员接收用户需求(clint_socket.recv(4096)) 接受用户需求之后 客服人员会根据用户说的话 挑选出用户要办理的业务(从用户请求中获取资源路径) 才能精确的为客户办理业务, 并且把结果反馈给客户(返回响应信息给浏览器 clint_socket.send(data))
多线程是因为用户会有很多
while True是因为用户可能不止要办理一项业务
下面这个图全面展示了TCP协议下浏览器与服务器之间的交互过程
提前准备 :我提前创建了一个templates目录 并且在里面写了两个HTML文件
面向过程:
import socket
import re
import threading
def muit_yonghu(s1):
request = s1.recv(4096)
print(request)
print(type(request))
# 请求头格式
data = "HTTP/1.1 200 OK\r\nServer: PWS3.0\r\n\r\n"
# 获取用户请求信息中的路径信息
w = re.findall(r'GET (.*?) HTTP/1.1\r\nHost: loc', request.decode())
print(w[0])
if w[0] == '/':
data = data + 'nav.html'
else:
# 拼接响应数据
try:
with open(f'./templates/{w[0]}', 'rb') as f:
res = f.read()
data = data + res.decode()
except:
data = data + '<h1>404 Page Not Found</h1>'
# 把信息传给浏览器
s1.send(data.encode())
s1.close()
def server():
# 创建服务器
s = socket.socket()
# 设置端口重用
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 服务器绑定端口便于客户访问
s.bind(('', 8000))
while True:
# 设置为监听模式,当用户访问时就会知道
s.listen(128)
# 当用户访问时,给用户分配一个分机,并且获取用户IP
s1, a = s.accept()
print(f'{a}用户已登录')
#获取浏览器发来的请求信息
t = threading.Thread(target = muit_yonghu, args = (s1, ))
t.start()
if __name__ == '__main__':
server()
面向对象:
class So(object):
def __init__(self):
#创建套接字
s = socket.socket()
#设置端口复用
s.setsockopt(socket.SOL_SOCKET, socket.SOCK_STREAM, 1)
#绑定端口
s.bind(('', 8080))
#设置监听模式
s.listen(128)
self.client_threed(s)
def client_threed(self, s):
while True:
#让用户访问并给用户分配一个分机
self.s1, a = s.accept()
print(f'{a}用户已登录')
t = threading.Thread(target=self.clint)
t.start()
def clint(self):
while True:
#接收用户请求信息
data = self.s1.recv(4096)
data = data.decode()
# print(data)
#从请求信息中获取资源路径
clint_data = re.findall(r'ET /(.*?) HTTP/1.1', data)
# print(clint_data[0])
send_data = "HTTP/1.1 200 OK\r\nServer: PWS3.0\r\n\r\n"
#返回资源给浏览器 try:如果用户清秀资源路径不存在 返回404
try:
with open(f'./templates/{clint_data[0]}', 'rb') as f:
w = f.read()
send_data = send_data + w.decode()
except:
send_data = send_data + '<h1>404 Page Not Found</h1>'
#将相应信息返回给用户
self.s1.send(send_data.encode())
if __name__ == '__main__':
s = So()