[TOC] 軟體開發架構 C/S架構 client:客戶端 server:服務端 優點:軟體的使用穩定,網路資源占用少 缺點: 若需要使用多個軟體,需要下載多個客戶端 服務端更新後,用戶也需要跟著下載更新 B/S架構 browser:瀏覽器 server:服務端 優點:以瀏覽器充當客戶端,服務端更新 ...
目錄
軟體開發架構
C/S架構
client:客戶端
server:服務端
優點:軟體的使用穩定,網路資源占用少
缺點:
- 若需要使用多個軟體,需要下載多個客戶端
- 服務端更新後,用戶也需要跟著下載更新
B/S架構
browser:瀏覽器
server:服務端
優點:以瀏覽器充當客戶端,服務端更新不需要用戶更新下載
缺點: 占用網路資源大,網路不好時,體驗差
互聯網OSI七層協議
從下往上分為:
物理層--> 數據鏈路層--> 網路層--> 傳輸層--> 會話層--> 表示層--> 應用層
物理層
傳輸電信號 0100011
數據鏈路層
規定好電信號的分組方式
必須要由一塊網卡
mac地址:12位唯一的16進位數
前6位是廠商號
後6位是流水號
乙太網協議:
- 在同一個區域網內通信
- 單播 1對1吼
- 廣播 多對多吼
- 會有廣播風暴, 不能對區域網通信
- 在同一個區域網內通信
網路層
ip:定位區域網位置
port: 埠,唯一標識一臺電腦上的一個程式
arp協議:將mac地址獲取,並解析成ipi地址
傳輸層
TCP協議
TCP協議稱之為流式協議
若想要通信,必須建立連接,並建立雙向通道
三次握手,四次揮手:
- 三次握手建立連接
- 客戶端往服務端發送建立通道
- 服務端要確認客戶端的請求,並往客戶端也發送請求建立通道
- 客戶端接收到服務端建立連接的請求,並返回確認
- 建立雙向通道
- 雙向通道
- 反饋機制
- 客戶端往服務端發送請求獲取數據,服務端務必返回數據,客戶端確認收到,否則會反覆發送,一直到某個時間段內,會停止發送
- 四次揮手斷連接
- 客戶端往服務端發送斷開連接請求,服務端返回確認收到
- 服務端需要再次發送斷開連接請求
- 客戶端返回確認收到
- 最終確認斷開來連接
UDP協議
- 數據不安全
- 不需要建立雙向通道
- 傳輸速度快
- 不會由粘包問題
- 客戶端發送數據,不需要服務端確認收到
應用層
ftp、http
socket套接字
socket用來寫套接字客戶端與服務端的模塊,內部幫我們封裝好了7層協議需要做的事情.
socket套接字模板
# 服務端
import socket
server = socket.socket()
server.bind(
('127.0.0.1', 9527)
)
server.listen(5)
while True:
conn, addr = server.accept()
print(addr)
while True:
try:
data = conn.recv(1024)
if len(data) == 0:
continue
print(data.decode('utf-8'))
conn.send(data)
except Exception as e:
print(e)
break
conn.close()
# 客戶端
import socket
client = socket.socket()
client.connect(
('127.0.0.1', 9527)
)
while True:
send_msg = input('客戶端:')
client.send(send_msg.encode('utf-8'))
data = client.recv(1024)
print(data.decode('utf-8'))
subprocess
用來通過代碼往cmd創建一個管道,並且發送命令和接收cmd返回的結果
# 偽代碼:
import subprocess
obj = subprocess.Popen(
'命令',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
msg = obj.stdout.read() + obj.stderr.read()
粘包問題
- 不能確定對方發送數據的大小
- 在短時間內,間隔時間短,並且數據量小的情況下,預設將這些數據打包成一個多次發送的數據,然後一次性發送
struct解決粘包問題
可以將一個數據的長度打包成一個固定長度的報頭.
struct.pack('模式i', '源數據長度')
data = 'gagawagwaga'
# 打包成報頭
headers = struct.pack('i', len(data))
# 解包獲取數據真實長度
data = struct.unpack('i', headers)[0]
# 服務端
import socket
import subprocess
import struct
server = socket.socket()
server.bind(
('127.0.0.1', 9527)
)
server.listen(5)
while True:
conn, addr = server.accept()
print(addr)
while True:
try:
cmd = conn.recv(1024).decode('utf-8')
if len(cmd) == 0:
continue
obj = subprocess.Popen(
cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
res = obj.stdout.read() + obj.stderr.read()
headers = struct.pack('i', len(res))
conn.send(headers)
conn.send(res)
except Exception as e:
print(e)
break
conn.close()
# 客戶端
import socket
import struct
client = socket.socket()
client.connect(
('127.0.0.1', 9527)
)
while True:
cmd = input('客戶端輸入命令:')
client.send(cmd.encode('utf-8'))
headers = client.recv(4)
data_len = struct.unpack('i', headers)[0]
data= client.recv(data_len)
print(data.decode('gbk'))
升級版: 先將數據存放到字典中,將字典打包發送過去
字典的好處:真實數據長度;文件的描述信息;發送的數據更小
socketserver
# 服務端
import socketserver
class MyTCPServer(socketserver.BaseRequestHandler):
def handle(self):
print(self.client_address)
while True:
try:
data = self.request.recv(1024).decode('utf-8')
send_msg = data.upper()
self.request.send(send_msg.encode('utf-8'))
except Exception as e:
print(e)
break
if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(
('127.0.0.1', 9527), MyTCPServer
)
server.serve_forever()