這篇文章將為大家詳細(xì)講解有關(guān)解決tcp粘包問題的辦法有哪些,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
創(chuàng)新互聯(lián)公司自2013年創(chuàng)立以來,公司以成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)、系統(tǒng)開發(fā)、網(wǎng)絡(luò)推廣、文化傳媒、企業(yè)宣傳、平面廣告設(shè)計等為主要業(yè)務(wù),適用行業(yè)近百種。服務(wù)企業(yè)客戶上千,涉及國內(nèi)多個省份客戶。擁有多年網(wǎng)站建設(shè)開發(fā)經(jīng)驗。為企業(yè)提供專業(yè)的網(wǎng)站建設(shè)、創(chuàng)意設(shè)計、宣傳推廣等服務(wù)。 通過專業(yè)的設(shè)計、獨特的風(fēng)格,為不同客戶提供各種風(fēng)格的特色服務(wù)。1 socket通信過程如圖所示:首先客戶端將發(fā)送內(nèi)容通過send()方法將內(nèi)容發(fā)送到客戶端計算機(jī)的內(nèi)核區(qū),然后由操作系統(tǒng)將內(nèi)容通過底層路徑發(fā)送到服務(wù)器端的內(nèi)核區(qū),然后由服務(wù)器程序通過recv()方法從服務(wù)器端計算機(jī)內(nèi)核區(qū)取出數(shù)據(jù)。
2 因此我們可以了解到,send方法并不是直接將內(nèi)容發(fā)送到服務(wù)器端,recv方法也并不是直接將從客戶端發(fā)來的內(nèi)容接收到服務(wù)器程序內(nèi)存中,而是操作自己機(jī)器的內(nèi)核區(qū)。
1 1:當(dāng)連續(xù)發(fā)送數(shù)據(jù)時,由于tcp協(xié)議的nagle算法,會將較小的內(nèi)容拼接成大的內(nèi)容,一次性發(fā)送到服務(wù)器端,因此造成粘包2 3 2:當(dāng)發(fā)送內(nèi)容較大時,由于服務(wù)器端的recv(buffer_size)方法中的buffer_size較小,不能一次性完全接收全部內(nèi)容,因此在下一次請求到達(dá)時,接收的內(nèi)容依然是上一次沒有完全接收完的內(nèi)容,因此造成粘包現(xiàn)象。
也就是說:
思路一:對于第一種粘包產(chǎn)生方式可以在兩次send()直接使用recv()來阻止連續(xù)發(fā)送的情況發(fā)生。代碼就不用展示了。
思路二:由于產(chǎn)生
方式一:分兩次通訊分別傳遞內(nèi)容大小和內(nèi)容
服務(wù)器端代碼:
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import subprocess server = socket(AF_INET, SOCK_STREAM) server.bind(("127.0.0.1", 8000)) server.listen(5) while True: conn, addr = server.accept() print("創(chuàng)建了一個新的連接!") while True: try: data = conn.recv(1024) if not data: break res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() if err: cmd_msg = err else: cmd_msg = res.stdout.read() if not cmd_msg: cmd_msg = "action success!".encode("gbk") length = len(cmd_msg) conn.send(str(length).encode("utf-8")) conn.recv(1024) conn.send(cmd_msg) except Exception as e: print(e) break
客戶端代碼:
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * client = socket(AF_INET, SOCK_STREAM) client.connect(("127.0.0.1", 8000)) while True: inp = input(">>:") if not inp: continue if inp == "quit": break client.send(inp.encode("utf-8")) length = int(client.recv(1024).decode("utf-8")) client.send("ready!".encode("utf-8")) lengthed = 0 cmd_msg = b"" while lengthed < length: cmd_msg += client.recv(1024) lengthed = len(cmd_msg) print(cmd_msg.decode("gbk"))
方式二:一次通訊直接傳遞內(nèi)容大小和內(nèi)容
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import subprocess import struct server = socket(AF_INET, SOCK_STREAM) server.bind(("127.0.0.1", 8000)) server.listen(5) while True: conn, addr = server.accept() print("創(chuàng)建了一個新的連接!") while True: try: data = conn.recv(1024) if not data: break res = subprocess.Popen(data.decode("utf-8"), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) err = res.stderr.read() if err: cmd_msg = err else: cmd_msg = res.stdout.read() if not cmd_msg: cmd_msg = "action success!".encode("gbk") length = len(cmd_msg) conn.send(struct.pack("i", length)) conn.send(cmd_msg) except Exception as e: print(e) break
# __author__:Kelvin # date:2019/4/28 21:36 from socket import * import struct client = socket(AF_INET, SOCK_STREAM) client.connect(("127.0.0.1", 8000)) while True: inp = input(">>:") if not inp: continue if inp == "quit": break client.send(inp.encode("utf-8")) length = struct.unpack("i",client.recv(4))[0] lengthed = 0 cmd_msg = b"" while lengthed < length: cmd_msg += client.recv(1024) lengthed = len(cmd_msg) print(cmd_msg.decode("gbk"))
關(guān)于解決tcp粘包問題的辦法有哪些就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。