亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

python粘包的解決方案

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

什么是粘包

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

服務端:

import socket
import struct

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

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

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

# 接受數(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('關閉服務')
        break

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

    # 向客戶端返回數(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,  # 管道一:輸出結果
                           stderr=subprocess.PIPE  # 管道二:輸出錯誤信息
                           )
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)

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

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

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

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

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

image-20240120212503635

但是根據(jù)客戶端的控制臺顯示數(shù)據(jù)在返回時被截斷了

其實原因很簡單:

response = client_socket.recv(1024)

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

客戶端
import socket

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

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

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

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

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

# 關閉連接
client_socket.close()
服務端
import socket

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

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

# 監(jiān)聽客戶端請求
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

實際情況:

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

導致粘包的原因

1.緩沖區(qū)大小限制:在TCP傳輸中,由于數(shù)據(jù)過大,超出緩存區(qū)大小限制,導致接收方不能接收到所有的數(shù)據(jù)包,造成了數(shù)據(jù)包的截斷或丟失

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

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

解決方案:struct模塊

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

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

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

msg_one = '你好'
msg_two = ('struct 是 Python 標準庫中的一個模塊,用于進行字節(jié)與數(shù)據(jù)類型之間的相互轉(zhuǎn)換。它提供了'
           '一組函數(shù)來打包(pack)和解包(unpack)數(shù)據(jù),使得數(shù)據(jù)在網(wǎng)絡傳輸或文件存儲時能夠以二進制形式進行處理。')
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é)流總大小讓接收端知曉,然后接收端來一個死循環(huán)接收完所有數(shù)據(jù)

客戶端
import socket
import struct

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

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

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

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


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

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

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

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

# 監(jiān)聽客戶端請求
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ù)該原理改進案例代碼

客戶端
import socket
import struct

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

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

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

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

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

    # 向客戶端返回數(shù)據(jù)
    client_socket.send(real_data)
服務端
import socket
import struct
import subprocess

# 獲取cmd指令
cmd_from_client = 'ipconfig'
cmd_msg = subprocess.Popen(cmd_from_client,
                           shell=True,  # 使用shell命令
                           stdout=subprocess.PIPE,  # 管道一:輸出結果
                           stderr=subprocess.PIPE  # 管道二:輸出錯誤信息
                           )
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)

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

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

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

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

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

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

相關文章

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

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

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

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

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

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

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

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

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

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

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

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

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

    Django 按組控制權限類及定義方法詳解

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

    使用Python橫向合并excel文件的實例

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

    對python中各個response的使用說明

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

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

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

最新評論