31 socket套接字 struct模塊
阿新 • • 發佈:2019-04-30
exce 問題 error: linux mac系統 pip 訪問 roc 間隔
socket(套接字)
基於socket實現客戶端與服務端通信
服務端套接字函數
s.bind() 綁定(主機,端口號)到套接字
s.listen() 開始TCP監聽
s.accept() 被動接受TCP客戶的連接,(阻塞式)等待連接的到來
客戶端套接字函數
s.connect() 主動初始化TCP服務器連接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
公共用途的套接字函數
s.recv() 接收TCP數據
s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩余空間時,數據丟失,不會發完)
socket初識
127.0.0.1:本地回環地址,只能本機訪問
-----------------------------服務端------------------------------ import socket server = socket.socket() # 類似於買手機 server.bind((‘127.0.0.1‘, 8080)) # 類似於插手機卡 bind((IP,PORT)) server.listen(5) # 開機 半連接池 conn, addr = server.accept() # 待機等待接電話 data= conn.recv(1024) # 接聽別人說話 只接收1024個字節 bytes print(data) conn.send(b‘hello!‘) # 跟別人說話 conn.close() # 關閉通信連接 server.close() # 關閉服務端 -----------------------------客戶端------------------------------ import socket client = socket.socket() client.connect((‘127.0.0.1‘, 8080)) # 找服務器 client.send(b‘hello how much?‘) data = client.recv(1024) print(data) client.close()
TCP協議的特點
會將數據量比較小的,並且時間間隔比較短的數據,一次性打包發送給接收端
-----------------------------服務端------------------------------ import socket server = socket.socket() server.bind((‘127.0.0.1‘,8088)) server.listen(5) # 半連接池 conn,addr = server.accept() data = conn.recv(1024) print(data) data = conn.recv(1024) print(data) data = conn.recv(1024) print(data) >>>:b‘hellohellohello‘ b‘‘ b‘‘ -----------------------------客戶端------------------------------ import socket client = socket.socket() client.connect((‘127.0.0.1‘,8088)) client.send(b‘hello‘) client.send(b‘hello‘) client.send(b‘hello‘)
通信循環
-----------------------------服務端------------------------------ import socket """ 服務端: 要有固定的ip和port 24小時不間斷提供服務 """ server = socket.socket() server.bind((‘127.0.0.1‘, 8080)) server.listen(5) conn, addr = server.accept() # 阻塞 while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0: break # 針對linux和mac系統 客戶端異常斷開反復收空的情況 print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() server.close() -----------------------------客戶端------------------------------ import socket client = socket.socket() client.connect((‘127.0.0.1‘, 8080)) while True: msg = input(‘>>>:‘).encode(‘utf-8‘) if len(msg) == 0: continue client.send(msg) data = client.recv(1024) print(data)
struct模塊
import struct data = ‘seionksngjgm,xmdnabnk ko‘ res = struct.pack(‘i‘,len(data)) print(‘res:‘,res) # res: b‘\x18\x00\x00\x00‘ print(‘len(res):‘,len(res)) # 4 ret = struct.unpack(‘i‘,res) print(‘ret:‘,ret) # (24,) print(‘ret[0]:‘,ret[0]) # 24
鏈接循環
-----------------------------服務端------------------------------ import socket import subprocess import struct import json """ 服務端: 要有固定的ip和port 24小時不間斷提供服務 """ server = socket.socket() server.bind((‘127.0.0.1‘, 8081)) server.listen(5) # 半連接池 while True: conn, addr = server.accept() # 阻塞 while True: try: data = conn.recv(1024).decode(‘utf-8‘) # 阻塞 if len(data) == 0: break # 針對linux和mac系統 客戶端異常斷開反復收空的情況 obj = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() print(len(stdout + stderr)) header_dic = { ‘filename‘: ‘cls.av‘, ‘len‘: len(stdout + stderr) } header_bytes = json.dumps(header_dic).encode(‘utf-8‘) # 制作報頭 header = struct.pack(‘i‘, len(header_bytes)) # 將需要發送給客戶端的數據打包成固定4個字節 conn.send(header) conn.send(header_bytes) conn.send(stdout + stderr) except ConnectionResetError: break conn.close() server.close() -----------------------------客戶端------------------------------ import socket import struct import json client = socket.socket() client.connect((‘127.0.0.1‘, 8081)) while True: msg = input(‘>>>:‘).encode(‘utf-8‘) if len(msg) == 0: continue client.send(msg) header = client.recv(4) # 對這個頭進行解包,獲取真實數據的長度 head_len = struct.unpack(‘i‘, header)[0] head_dic = json.loads(client.recv(head_len).decode(‘utf-8‘)) print(head_dic) # 對需要接受的數據 進行循環接收 total_size = head_dic[‘len‘] recv_size = 0 res = b‘‘ while recv_size < total_size: data = client.recv(1024) res += data recv_size += len(data) print(res.decode(‘gbk‘))
粘包問題
-----------------------------服務端------------------------------ import socket """ 服務端: 要有固定的ip和port 24小時不間斷提供服務 """ server = socket.socket() server.bind((‘127.0.0.1‘, 8080)) server.listen(5) # 半連接池 while True: conn, addr = server.accept() # 阻塞 while True: try: data = conn.recv(1024) # 阻塞 if len(data) == 0: break # 針對linux和mac系統 客戶端異常斷開反復收空的情況 print(data) conn.send(data.upper()) except ConnectionResetError: break conn.close() server.close() -----------------------------客戶端------------------------------ import socket client = socket.socket() client.connect((‘127.0.0.1‘, 8080)) while True: msg = input(‘>>>:‘).encode(‘utf-8‘) if len(msg) == 0: continue client.send(msg) data = client.recv(1024) print(data)
最終方法:解決粘包問題
1.先發報頭
2.再發字典
3.再發你的真實數據
1.先收4個長度的報頭
2.解包拿到字典數據長度
3.接收字典(反序列化) 》》》 獲取字典裏面所有信息
4.接收真實數據
31 socket套接字 struct模塊