解决socket粘包的两种low版模式 os.popen()和struct模块
生活随笔
收集整理的這篇文章主要介紹了
解决socket粘包的两种low版模式 os.popen()和struct模块
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
無注釋版
os.popen()模式
server端
import socket import osphone = socket.socket() phone.bind(("localhost",8088)) phone.listen()while 1:conn,addr = phone.accept()while 1:try:from_client_data = conn.recv(1024)if from_client_data.upper() == b'Q':print("客戶端退出")breakprint(from_client_data.decode('utf-8'))cmd_res = os.popen(from_client_data.decode("utf-8")).read()if len(cmd_res) == 0:cmd_res = "cmd hs no output..."print(len(cmd_res.encode('gbk')))conn.send(str(len(cmd_res.encode('gbk'))).encode('gbk'))client.ack = conn.recv(1024)conn.send(cmd_res.encode('gbk'))except ConnectionResetError:breakconn.close() phone.close()client端
import socket phone = socket.socket() phone.connect(('localhost',8088)) while 1:client_data = input(">>>")if not client_data:print("發(fā)送的內(nèi)容不能為空")continuephone.send(client_data.encode("utf-8"))if client_data.upper() == "Q":quit()else:server_data = phone.recv(1024)phone.send("準(zhǔn)備好接收了".encode('utf-8'))total_size = int(server_data.decode('gbk'))total_data = b''while 1:if len(total_data) < total_size:total_data += phone.recv(1024)print(len(total_data))else:breakprint(total_data.decode('gbk')) phone.close()struct模塊解決粘包
server端
import socket import subprocess import structphone = socket.socket() phone.bind(("localhost",8088)) phone.listen(5)while 1:conn,addr = phone.accept()print(addr)while 1:try:from_client_data = conn.recv(1024)if from_client_data.upper() == b'Q':print("客戶端退出")breakprint(from_client_data.decode('utf-8'))obj = subprocess.Popen(from_client_data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)ret = obj.stdout.read()+obj.stderr.read()total_size = len(ret)header = struct.pack('i',total_size)print(total_size)conn.send(header)conn.send(ret)except ConnectionResetError:breakconn.close() phone.close()client端
import socket import struct phone = socket.socket() phone.connect(('localhost',8088)) while 1:client_data = input(">>>")if not client_data:print("發(fā)送的內(nèi)容不能為空")continuephone.send(client_data.encode("utf-8"))if client_data.upper() == "Q":quit()else:server_data = phone.recv(4)total_size = struct.unpack('i',server_data)[0]total_data = b''while 1:if len(total_data) < total_size:total_data += phone.recv(1024)print(len(total_data))else:breakprint(total_data.decode('gbk'))# print(int(server_data.decode('gbk'))) phone.close()有注釋版
os.popen()模式
server端
import socket import osphone = socket.socket() # 實(shí)例化一個(gè)socket對(duì)象phone.bind(("localhost",8088)) # 綁定地址(host,port)到套接字,在AF_INET下,以元組(host,port)的形式表示地址phone.listen(5) # 開始TCP監(jiān)聽。backlog指定在拒絕連接之前,操作系統(tǒng)可以掛起的最大連接數(shù)量。該值至少為1,大部分應(yīng)用程序設(shè)為5就可以了。while 1: # 開啟循環(huán),多個(gè)用戶同時(shí)連接(當(dāng)然不是并發(fā),排隊(duì)連接)conn,addr = phone.accept()# 被動(dòng)接受TCP客戶端連接,(阻塞式)等待連接的到來,會(huì)有兩個(gè)值,conn我也不明白是什么值,addr是客戶端連接的地址while 1: # 客戶端與服務(wù)端多次對(duì)話,客戶端多次執(zhí)行循環(huán)try: # 異常處理,客戶端直接退出ConnectionResetError錯(cuò)誤from_client_data = conn.recv(1024) # 接收客戶端數(shù)據(jù)if from_client_data.upper() == b'Q': # 判斷客戶端輸入是否是q或Q,如果是q,直接退出當(dāng)前連接print("客戶端退出")breakprint(from_client_data.decode('utf-8')) # 輸出客戶端轉(zhuǎn)碼后的數(shù)據(jù)cmd_res = os.popen(from_client_data.decode("utf-8")).read() # 執(zhí)行os命令,通過popen執(zhí)行cmd命令if len(cmd_res) == 0: # 如果沒有該命令,返回下面結(jié)果cmd_res = "cmd hs no output..."conn.send(str(len(cmd_res.encode('gbk'))).encode('gbk')) # 發(fā)送數(shù)據(jù),首先計(jì)算cmd_res的gbk字節(jié)長度,然后轉(zhuǎn)換成字符串發(fā)送給客戶端,因?yàn)閕nt型不能發(fā)送print(len(cmd_res.encode('gbk'))) # 輸出該命令返回的長度conn.send(cmd_res.encode('gbk')) # 執(zhí)行一個(gè)接收,截?cái)嗌舷聝蓚€(gè)的粘包c(diǎn)onn.send(cmd_res.encode('gbk')) # 發(fā)送給客戶端except ConnectionResetError:breakconn.close() # 關(guān)閉連接 phone.close() # 關(guān)閉連接client端
import socket phone = socket.socket() # 實(shí)例化對(duì)象 phone.connect(('localhost',8088)) # 主動(dòng)初始化TCP服務(wù)器連接,。一般address的格式為元組(hostname,port),如果連接出錯(cuò),返回socket.error錯(cuò)誤。 while 1: # 循環(huán)輸入client_data = input(">>>")if not client_data: # 如果輸入為空,not client_data 則為Trueprint("發(fā)送的內(nèi)容不能為空")continuephone.send(client_data.encode("utf-8")) # 給服務(wù)端發(fā)送信息if client_data.upper() == "Q": # q退出quit()else:server_data = phone.recv(1024) # 接收返回的字節(jié)長度phone.send("準(zhǔn)備好接收了".encode('utf-8')) # 給服務(wù)端發(fā)送消息,阻塞服務(wù)端上下造成粘包的問題(low版)total_size = int(server_data.decode('gbk')) # 接收到的是字符串,轉(zhuǎn)換成整型total_data = b'' # 剛開始設(shè)置為0,空字符串則為0,前面加b表示字節(jié)while 1: # 如果我收到的字節(jié)小于total_size,則一直循環(huán)if len(total_data) < total_size:total_data += phone.recv(1024) # 每次把信息加到total_data中print(len(total_data))else:breakprint(total_data.decode('gbk')) # 輸出返回的結(jié)果 phone.close() # 關(guān)閉連接struct模塊解決粘包
server端
import socket import subprocess import structphone = socket.socket() # 實(shí)例化一個(gè)socket對(duì)象 phone.bind(("localhost",8088)) # 綁定地址(host,port)到套接字,在AF_INET下,以元組(host,port)的形式表示地址 phone.listen(5) # 開始TCP監(jiān)聽。backlog指定在拒絕連接之前,操作系統(tǒng)可以掛起的最大連接數(shù)量。該值至少為1,大部分應(yīng)用程序設(shè)為5就可以了。while 1:# 開啟循環(huán),多個(gè)用戶同時(shí)連接(當(dāng)然不是并發(fā),排隊(duì)連接)conn,addr = phone.accept()# 被動(dòng)接受TCP客戶端連接,(阻塞式)等待連接的到來,會(huì)有兩個(gè)值,conn我也不明白是什么值,addr是客戶端連接的地址print(addr)while 1: # 客戶端與服務(wù)端多次對(duì)話,客戶端多次執(zhí)行循環(huán)try: # 異常處理,客戶端直接退出ConnectionResetError錯(cuò)誤from_client_data = conn.recv(1024) # 接收客戶端數(shù)據(jù)if from_client_data.upper() == b'Q': # 判斷客戶端輸入是否是q或Q,如果是q,直接退出當(dāng)前連接print("客戶端退出")breakprint(from_client_data.decode('utf-8')) # 輸出客戶端轉(zhuǎn)碼后的數(shù)據(jù)obj = subprocess.Popen(from_client_data.decode('utf-8'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,)# subprocess 模塊中的代碼# shell: 命令解釋器,相當(dāng)于調(diào)用cmd 執(zhí)行指定的命令。# stdout:正確結(jié)果丟到管道中。# stderr:錯(cuò)了丟到另一個(gè)管道中。# windows操作系統(tǒng)的默認(rèn)編碼是gbk編碼。ret = obj.stdout.read()+obj.stderr.read() # 加的是字節(jié)# 正確的輸出跟錯(cuò)誤的輸出加起來,因?yàn)檎_輸出時(shí),錯(cuò)誤輸出為空,所以加起來相當(dāng)于0+1,沒什么區(qū)別total_size = len(ret) # 計(jì)算返回命令的長度header = struct.pack('i',total_size) # 將一個(gè)數(shù)字轉(zhuǎn)化成等長度的bytes類型。print(total_size) # 打印出返回命令的長度conn.send(header) # 發(fā)送固定長度的報(bào)頭conn.send(ret) # 給客戶端發(fā)送返回命令的結(jié)果except ConnectionResetError: breakconn.close() # 關(guān)閉連接 phone.close() # 關(guān)閉連接client端
import socket import struct phone = socket.socket() # 實(shí)例化對(duì)象 phone.connect(('localhost',8088)) # 主動(dòng)初始化TCP服務(wù)器連接,。一般address的格式為元組(hostname,port),如果連接出錯(cuò),返回socket.error錯(cuò)誤。 while 1: # 循環(huán)輸入client_data = input(">>>")if not client_data: # 如果輸入為空,not client_data 則為Trueprint("發(fā)送的內(nèi)容不能為空")continuephone.send(client_data.encode("utf-8")) # 給服務(wù)端發(fā)送信息if client_data.upper() == "Q": # q退出quit()else:server_data = phone.recv(4) # 接收?qǐng)?bào)頭長度total_size = struct.unpack('i',server_data)[0] # 反解報(bào)頭total_data = b'' # 剛開始設(shè)置為0,空字符串則為0,前面加b表示字節(jié)while 1: # 如果我收到的字節(jié)小于total_size,則一直循環(huán)if len(total_data) < total_size: total_data += phone.recv(1024) # 每次把信息加到total_data中print(len(total_data))else:breakprint(total_data.decode('gbk')) # 輸出返回的結(jié)果,windows默認(rèn)gbk# print(int(server_data.decode('gbk'))) phone.close() # 關(guān)閉連接轉(zhuǎn)載于:https://www.cnblogs.com/alex3174/p/11360954.html
總結(jié)
以上是生活随笔為你收集整理的解决socket粘包的两种low版模式 os.popen()和struct模块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数坑
- 下一篇: 写爬虫,不会正则怎么行?