欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

python粘包的解決方案

 更新時(shí)間:2024年01月21日 10:34:33   作者:Az_plus  
粘包就是在數(shù)據(jù)傳輸過程中有多個(gè)數(shù)據(jù)包被粘連在一起被發(fā)送或接受,本文主要介紹了python粘包的解決方案,具有一定的參考價(jià)值,感興趣的可以了解一下

什么是粘包

粘包就是在數(shù)據(jù)傳輸過程中有多個(gè)數(shù)據(jù)包被粘連在一起被發(fā)送或接受

服務(wù)端:

import socket
import struct

# 創(chuàng)建Socket
Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定服務(wù)器和端口號(hào)
servers_addr = ('127.0.0.1', 8081)
Socket.bind(servers_addr)

# 監(jiān)聽客戶端請(qǐng)求 最大連接數(shù)為5
Socket.listen(5)
print('服務(wù)器啟動(dòng)成功,等待客戶端連接...')

# 接受數(shù)據(jù)
client_socket, client_addr = Socket.accept()
print('與客戶端建立連接', client_addr)
client_socket.setblocking(False)
# 數(shù)據(jù)交換
while True:
    data = client_socket.recv(10880)  # 最大1024字節(jié)
    if len(data) < 1:
        print('關(guān)閉服務(wù)')
        break

    # 接受客戶器端傳來的數(shù)據(jù)
    print(data.decode())

    # 向客戶端返回?cái)?shù)據(jù)
    client_socket.sendall(data)
    break
Socket.close()

客戶端:

import socket
import subprocess

# 獲取cmd指令
cmd_from_client = 'ipconfig'
cmd_msg = subprocess.Popen(cmd_from_client,
                           shell=True,  # 使用shell命令
                           stdout=subprocess.PIPE,  # 管道一:輸出結(jié)果
                           stderr=subprocess.PIPE  # 管道二:輸出錯(cuò)誤信息
                           )
msg_one = cmd_msg.stdout.read().decode('gbk')
msg_two = cmd_msg.stderr.read().decode('gbk')
msg = msg_one + msg_two


# 創(chuàng)建Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 服務(wù)器地址和端口
server_address = ('localhost', 8081)

# 連接服務(wù)器
client_socket.connect(server_address)
print('已連接到服務(wù)器:', server_address)

while True:
    # 發(fā)送數(shù)據(jù)
    # message = input('>>>>')
    client_socket.sendall(msg.encode())

    # 接收響應(yīng)
    response = client_socket.recv(1024)
    print('服務(wù)器響應(yīng):', response.decode())
    break
client_socket.close()

案例中使用了subprocess模塊輸出了ip信息,在服務(wù)端打印的數(shù)據(jù)中可以看到內(nèi)容是能夠正常輸出的

image-20240120212503635

但是根據(jù)客戶端的控制臺(tái)顯示數(shù)據(jù)在返回時(shí)被截?cái)嗔?/p>

其實(shí)原因很簡單:

response = client_socket.recv(1024)

數(shù)據(jù)在服務(wù)端中能一次性的接收,但由于客戶端只能接受1024,所以就不會(huì)從緩存中一下取完大于1024的那部分?jǐn)?shù)據(jù),其實(shí)不管是客戶端還是服務(wù)端,recv()的緩存區(qū)大小都是可控的,但是發(fā)送方發(fā)送了一個(gè) 10KB 的數(shù)據(jù)包,而接收方使用 recv(1024) 只能一次接收最多 1KB 的數(shù)據(jù),這樣就需要多次調(diào)用 recv() 來接收完整的數(shù)據(jù),可能會(huì)引發(fā)粘包問題

客戶端
import socket

# 創(chuàng)建 Socket 對(duì)象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 服務(wù)器地址和端口
server_address = ('localhost', 8081)

# 連接服務(wù)器
client_socket.connect(server_address)
print('已連接到服務(wù)器:', server_address)

# 發(fā)送數(shù)據(jù)包
message1 = 'Hello'
message2 = 'World'

# 連續(xù)發(fā)送兩個(gè)數(shù)據(jù)包
client_socket.sendall(message1.encode())
client_socket.sendall(message2.encode())

# 關(guān)閉連接
client_socket.close()
服務(wù)端
import socket

# 創(chuàng)建 Socket 對(duì)象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定服務(wù)器地址和端口
server_address = ('localhost', 8081)
server_socket.bind(server_address)

# 監(jiān)聽客戶端請(qǐng)求
server_socket.listen(1)
print('等待客戶端連接...')

while True:
    # 接受連接
    client_socket, client_addr = server_socket.accept()
    print('與客戶端建立連接:', client_addr)

    # 接收數(shù)據(jù)
    data = client_socket.recv(1024)  # 接收數(shù)據(jù)包
    received_data = data.decode()

    # 處理接收到的數(shù)據(jù)
    print('接收到數(shù)據(jù):', received_data)

理想情況:

等待客戶端連接...
與客戶端建立連接: ('127.0.0.1', 61127)
接收到數(shù)據(jù): Hello
接收到數(shù)據(jù): World

實(shí)際情況:

等待客戶端連接...
與客戶端建立連接: ('127.0.0.1', 61127)
接收到數(shù)據(jù): HelloWorld

導(dǎo)致粘包的原因

1.緩沖區(qū)大小限制:在TCP傳輸中,由于數(shù)據(jù)過大,超出緩存區(qū)大小限制,導(dǎo)致接收方不能接收到所有的數(shù)據(jù)包,造成了數(shù)據(jù)包的截?cái)嗷騺G失

2.底層協(xié)議特性:底層傳輸協(xié)議如 TCP 是面向流的,不保留消息邊界。TCP 協(xié)議會(huì)將數(shù)據(jù)流切分為適當(dāng)大小的數(shù)據(jù)塊進(jìn)行傳輸,因此無法保證每個(gè)數(shù)據(jù)包的邊界

3.數(shù)據(jù)發(fā)送速度過快:發(fā)送方連續(xù)發(fā)送數(shù)據(jù)包,而接收方無法及時(shí)處理,導(dǎo)致多個(gè)數(shù)據(jù)包在接收緩沖區(qū)中堆積

解決方案:struct模塊

利用pack()方法將任意長度的 數(shù)字 打包成新的數(shù)據(jù)

再用unpack()方法將固定長度的 數(shù)字 解包成打包前數(shù)據(jù)真實(shí)的長度

  • pack()方法 第一個(gè)參數(shù)是格式,第二個(gè)參數(shù)是整數(shù)(數(shù)據(jù)的長度),返回值是一個(gè)新的數(shù)據(jù)
  • unpack()方法 第一個(gè)參數(shù)是格式,第二個(gè)參數(shù)是 pack()方法打包后生成的新數(shù)據(jù),返回值是一個(gè)元組,元組中放著打包前數(shù)據(jù)真實(shí)的長度
import struct

msg_one = '你好'
msg_two = ('struct 是 Python 標(biāo)準(zhǔn)庫中的一個(gè)模塊,用于進(jìn)行字節(jié)與數(shù)據(jù)類型之間的相互轉(zhuǎn)換。它提供了'
           '一組函數(shù)來打包(pack)和解包(unpack)數(shù)據(jù),使得數(shù)據(jù)在網(wǎng)絡(luò)傳輸或文件存儲(chǔ)時(shí)能夠以二進(jìn)制形式進(jìn)行處理。')
total = len(msg_one) + len(msg_two)  # 106

# 將數(shù)據(jù)打包
res = struct.pack('i', total)

# 解包數(shù)據(jù)
un_res = struct.unpack('i', res)

print(len(res))  # 4
print(res)  # bytes類型:  b'j\x00\x00\x00'
print(un_res)  # 元組類型: (106,)

粘包問題的根源在于,接收端不知道發(fā)送端將要傳送的字節(jié)流的長度,所以解決粘包的方法就是圍繞,如何讓發(fā)送端在發(fā)送數(shù)據(jù)前,把自己將要發(fā)送的字節(jié)流總大小讓接收端知曉,然后接收端來一個(gè)死循環(huán)接收完所有數(shù)據(jù)

客戶端
import socket
import struct

# 創(chuàng)建 Socket 對(duì)象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 服務(wù)器地址和端口
server_address = ('localhost', 8081)

# 連接服務(wù)器
client_socket.connect(server_address)
print('已連接到服務(wù)器:', server_address)

# 發(fā)送數(shù)據(jù)包
msg = b'helloworld'
data = struct.pack('i', len(msg))


# 先發(fā)送報(bào)頭
client_socket.send(data)

# 發(fā)送真實(shí)數(shù)據(jù)
client_socket.send(msg)
服務(wù)端
import socket
import struct

# 創(chuàng)建 Socket 對(duì)象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定服務(wù)器地址和端口
server_address = ('localhost', 8081)
server_socket.bind(server_address)

# 監(jiān)聽客戶端請(qǐng)求
server_socket.listen(1)
print('等待客戶端連接...')

while True:
    # 接受連接
    client_socket, client_addr = server_socket.accept()
    print('與客戶端建立連接:', client_addr)

    # 接收數(shù)據(jù)
    data = client_socket.recv(1024)  # 接收數(shù)據(jù)包
    received_data = struct.unpack('i', data)
    data_len = received_data[0]

    real_data = client_socket.recv(data_len)

    # 處理接收到的數(shù)據(jù)
    print('接收到數(shù)據(jù):', real_data.decode('utf8'))

根據(jù)該原理改進(jìn)案例代碼

客戶端
import socket
import struct

# 創(chuàng)建Socket
Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 綁定服務(wù)器和端口號(hào)
servers_addr = ('127.0.0.1', 8082)
Socket.bind(servers_addr)

# 監(jiān)聽客戶端請(qǐng)求 最大連接數(shù)為5
Socket.listen(5)
print('服務(wù)器啟動(dòng)成功,等待客戶端連接...')

# 接受數(shù)據(jù)
client_socket, client_addr = Socket.accept()
print('與客戶端建立連接', client_addr)
# client_socket.setblocking(False)
# 數(shù)據(jù)交換
while True:
    # 接受報(bào)頭
    header = client_socket.recv(4)  # 最大1024字節(jié)
    if len(header) < 1:
        print('關(guān)閉服務(wù)')
        break
    data_len = struct.unpack('i', header)[0]
    print(data_len)

    # 接受真實(shí)數(shù)據(jù)
    real_data = client_socket.recv(data_len)
    print(real_data.decode('gbk'))

    # 向客戶端返回?cái)?shù)據(jù)
    client_socket.send(real_data)
服務(wù)端
import socket
import struct
import subprocess

# 獲取cmd指令
cmd_from_client = 'ipconfig'
cmd_msg = subprocess.Popen(cmd_from_client,
                           shell=True,  # 使用shell命令
                           stdout=subprocess.PIPE,  # 管道一:輸出結(jié)果
                           stderr=subprocess.PIPE  # 管道二:輸出錯(cuò)誤信息
                           )
msg_one = cmd_msg.stdout.read().decode('gbk')
msg_two = cmd_msg.stderr.read().decode('gbk')
msg = msg_one + msg_two

# 創(chuàng)建Socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 服務(wù)器地址和端口
server_address = ('localhost', 8082)

# 連接服務(wù)器
client_socket.connect(server_address)
print('已連接到服務(wù)器:', server_address)

while True:
    # 先發(fā)報(bào)頭
    data_len = struct.pack('i', len(msg))
    client_socket.send(data_len)

    # 發(fā)送數(shù)據(jù)
    client_socket.send(msg.encode('gbk'))

    # 接收響應(yīng)
    response = client_socket.recv(data_len[0])
    print('服務(wù)器響應(yīng):', response.decode('gbk'))

到此這篇關(guān)于python粘包的解決方案的文章就介紹到這了,更多相關(guān)python 粘包內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python使用遺傳算法解決最大流問題

    Python使用遺傳算法解決最大流問題

    這篇文章主要為大家詳細(xì)介紹了Python使用遺傳算法解決最大流問題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 如何利用python給微信公眾號(hào)發(fā)消息實(shí)例代碼

    如何利用python給微信公眾號(hào)發(fā)消息實(shí)例代碼

    使用過微信公眾號(hào)的小伙伴應(yīng)該知道微信公眾號(hào)有時(shí)候會(huì)給你推一些文章,當(dāng)你選擇它的某個(gè)功能時(shí),它還會(huì)返回一些信息,下面這篇文章主要給大家介紹了關(guān)于如何利用python給微信公眾號(hào)發(fā)消息的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • Python簡易版圖書管理系統(tǒng)

    Python簡易版圖書管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Python如何實(shí)現(xiàn)簡易版圖書管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • python讀取圖片顏色值并生成excel像素畫的方法實(shí)例

    python讀取圖片顏色值并生成excel像素畫的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于python讀取圖片顏色值并生成excel像素畫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • python操作redis數(shù)據(jù)庫的三種方法

    python操作redis數(shù)據(jù)庫的三種方法

    這篇文章主要介紹了python操作redis數(shù)據(jù)庫的三種方法,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-09-09
  • python實(shí)現(xiàn)飛機(jī)大戰(zhàn)(面向過程)

    python實(shí)現(xiàn)飛機(jī)大戰(zhàn)(面向過程)

    這篇文章主要為大家詳細(xì)介紹了python面向過程實(shí)現(xiàn)飛機(jī)大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Django 按組控制權(quán)限類及定義方法詳解

    Django 按組控制權(quán)限類及定義方法詳解

    這篇文章主要為大家介紹了Django 按組控制權(quán)限類及定義方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 使用Python橫向合并excel文件的實(shí)例

    使用Python橫向合并excel文件的實(shí)例

    今天小編就為大家分享一篇使用Python橫向合并excel文件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • 對(duì)python中各個(gè)response的使用說明

    對(duì)python中各個(gè)response的使用說明

    今天小編就為大家分享一篇對(duì)python中各個(gè)response的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Python3基礎(chǔ)之基本數(shù)據(jù)類型概述

    Python3基礎(chǔ)之基本數(shù)據(jù)類型概述

    這篇文章主要介紹了Python3的基本數(shù)據(jù)類型,需要的朋友可以參考下
    2014-08-08

最新評(píng)論