描述:
可以用一個小故事來生動描述用戶與服務器交互的原理 移動公司式理解
要能辦理用戶手機業務需求 首先要先開一個移動公司, 有一個總檯(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()