python 黏包

來源:互聯網
上載者:User

標籤:inf   unp   服務   put   accept   gpo   需要   模組   最佳化演算法   

黏包黏包的起因:

連續send多個小資料,會發生黏包現象,這個是tcp協議最佳化演算法造成的

當發送一個資料超過本次接收的最大範圍之後,剩下的資料會留到下次接收時接收

黏包的現象:
import socketsk = socket.socket()sk.bind((‘127.0.0.1‘,8090))sk.listen()conn,addr = sk.accept()ret = conn.recv(2)   #在這裡先接收一個兩位元組的內容ret2 = conn.recv(10) #然後在這裡在接收一個長度為10位元組的內容print(ret)print(ret2)conn.close()sk.close()
import socketsk = socket.socket()sk.connect((‘127.0.0.1‘,8090))sk.send(b‘helloeve‘)  #在這裡發送一個長度為8的位元組sk.close()

b‘he‘
b‘lloeve‘

可以看見接收的內容被分開了

import socketsk = socket.socket()sk.bind((‘127.0.0.1‘,8090))sk.listen()conn,addr = sk.accept()ret1 = conn.recv(12)  #在這裡接收兩次print(ret1)ret2 = conn.recv(12)print(ret2)conn.close()sk.close()
import socketsk = socket.socket()sk.connect((‘127.0.0.1‘,8090))sk.send(b‘hello‘)  #這裡連續發送兩次資料sk.send(b‘eve‘)sk.close()

b‘helloeve‘
b‘‘

原本預計的接收兩個內容被合成一個接收了

這就是黏包

所以,黏包的根本原因就是,接收方不知道本次接收的資料具體大小,才會發生黏包

如何解決黏包

竟然知道是什麼原因才發生黏包,那麼,只要每次發送資料前,告訴對方我要發多少資料不就行了

import socketsk = socket.socket()sk.bind((‘127.0.0.1‘,8080))sk.listen()conn,addr = sk.accept()while True:    cmd = input(‘>>>‘)    if cmd == ‘q‘:        conn.send(b‘q‘)        break    conn.send(cmd.encode(‘gbk‘))    num = conn.recv(1024).decode(‘utf-8‘)  #將接到的長度賦給一個變數    conn.send(b‘ok‘)                        #想使用者端發送訊息表示已經接收到長度    res = conn.recv(int(num)).decode(‘gbk‘)  # 將接收到的長度值給接收位元組數    print(res)conn.close()sk.close()
import socketimport subprocess      #調用subprocess模組sk = socket.socket()sk.connect((‘127.0.0.1‘,8080))while True:    cmd = sk.recv(1024).decode(‘gbk‘)    if cmd == ‘q‘:        break    res = subprocess.Popen(cmd,shell=True,                     stdout=subprocess.PIPE,    #將取到的東西放到管道裡                     stderr=subprocess.PIPE)    # PIPE 管道    std_out = res.stdout.read()       #將管道裡的資料賦給一個變數    std_err = res.stderr.read()       #因為管道裡的東西只能取一次    sk.send(str(len(std_out)+len(std_err)).encode(‘utf-8‘))   #叫測量的長度發給服務端    sk.recv(1024)       #接收服務端的反饋    sk.send(std_out)    # 將資料發過去    sk.send(std_err)sk.close()

這樣每次發送前都將本次要發送的資料位元組數發過去,讓對方對應接收就不會發生黏包現象了

不過,雖然不會黏包,但是每次發送都需要一次互動,增加了代碼的工作

怎麼才能一次互動就解決這些問題呢

這時候就要用到

struct模組

struct模組可以把一個類型轉成固定長度的bytes

我們這次只需要用到int

import structimport socketsk = socket.socket()sk.bind((‘127.0.0.1‘,8080))sk.listen()conn,addr = sk.accept()while True:    cmd = input(‘>>>‘)    if cmd == ‘q‘:        conn.send(b‘q‘)        break    conn.send(cmd.encode(‘gbk‘))    num = conn.recv(4)               #接受用戶端的傳來的    num = struct.unpack(‘i‘,num)[0]  #反向得到位元組數    res = conn.recv(int(num)).decode(‘gbk‘)  #將位元組數傳給接收端當參數    print(res)               conn.close()sk.close()
import struct    #這時候就需要用到struct模組import socketimport subprocesssk = socket.socket()sk.connect((‘127.0.0.1‘,8080))while True:    cmd = sk.recv(1024).decode(‘gbk‘)    if cmd == ‘q‘:        break    res = subprocess.Popen(cmd,shell=True,                     stdout=subprocess.PIPE,                     stderr=subprocess.PIPE)    std_out = res.stdout.read()    std_err = res.stderr.read()    len_num = len(std_out)+len(std_err)   #將計算的位元組數賦給一個變數    num_by = struct.pack(‘i‘,len_num)     #在將位元組數用strect模組轉成長度為4的bytes    sk.send(num_by)                       #然後將它發給服務端    sk.send(std_out)    sk.send(std_err)sk.close()
在網路上傳輸的所有資料 都叫資料包
資料包裡的所有資料 都叫報文
報文裡不止有你的資料 還有 ip地址 mac地址 連接埠號碼

所有的報文 都有 前序

python 黏包

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.