Python Day33 粘包問題及粘包解決方案

2022-07-30 15:42:10 字數 4238 閱讀 6577

#

# tcp粘包問題

```python

粘包指的是資料與資料之間沒有明確的分界線,導致不能正確讀取資料!

tcp協議也稱之為流式協議(udp稱為資料報協議)

應用程式無法直接操作硬體,應用程式想要傳送資料則必須將資料交給作業系統,而作業系統需要需要同時為所有應用程式提供資料傳輸服務,也就意味著,作業系統不可能立馬就能將應用程式的資料傳送出去,就需要為應用程式提供乙個緩衝區,用於臨時存放資料,具體流程如下:

#傳送方:

當應用程式呼叫send函式時,應用程式會將資料從應用程式拷貝到作業系統快取,再由作業系統從緩衝區讀取資料並傳送出去

#接收方:

對方計算機收到資料也是作業系統先收到,至於應用程式何時處理這些資料,作業系統並不清楚,所以同樣需要將資料先儲存到作業系統的緩衝區中,當應用程式呼叫recv時,實際上是從作業系統緩衝區中將資料拷貝到應用程式的過程

1.傳送方傳送的資料長度每個作業系統會有不同的限制,資料超過限制則無法傳送

2.接收方接收資料時如果應用程式的提供的快取容量小於資料報的長度將造成資料丟失,而緩衝區大小不可能無限大

#tcp:

當我們需要傳輸較大的資料,或需要保證資料完整性時,最簡單的方式就是使用tcp協議了

與udp不同的是,tcp增加了一套校驗規則來保證資料的完整性,會將超過tcp包最大長度的資料拆分為多個tcp包 並在傳輸資料時為每乙個tcp資料報指定乙個順序號,接收方在收到tcp資料報後按照順序將資料報進行重組,重組後的資料全都是二進位制資料,且每次收到的二進位制資料之間沒有明顯的分界

'基於這種工作機制tcp在三種情況下會傳送粘包問題

1.當單個資料報較小時接收方可能一次性讀取了多個包的資料

2.當整體資料較大時接收方可能一次僅讀取了乙個包的一部分內容

3.另外tcp協議為了提高效率,增加了一種優化機制,會將資料較小且傳送間隔較短的資料合併傳送,該機制也會導致傳送方將兩個資料報粘在一起傳送

```#

# 解決粘包問題

```python

'首先明確只有tcp會出現粘包問題,之所以粘包是因為接收方不知道一次該接收的資料長度,那如何才能讓接收方知道資料的長度呢?

但是由於negle優化機制的存在,長度資訊和資料還是有可能會粘包,而接受方並不知道長度資訊具體幾個位元組,所以現在的問題是如何能夠長度資訊做成乙個固定長度的bytes數

我們可以將字串拼接為乙個固定長度的字元 但是這樣太麻煩,struct模組為我們提供了乙個功能,可以將整數型別轉換為固定長度的bytes,此時就派上用場了

```#

# 解決粘包後:

## 客戶端

```pytho

import

socket

import

struct

c =socket.socket()

c.connect((

"127.0.0.1

",8888))

while

true:

cmd = input("

>>>:

").strip()

c.send(cmd.encode(

"utf-8"))

data = c.recv(4)

length = struct.unpack("i"

,data)[0]

print

(length)

size =0

res = b""

while size temp = c.recv(1024)

size +=len(temp)

res +=temp

print(res.decode("

gbk"

))```

## 服務端

```python

import

socket

import

subprocess

import

struct

server =socket.socket()

server.bind((

"127.0.0.1

",8888))

server.listen()

while

true:

client, addr =server.accept()

while

true:

cmd = client.recv(1024).decode("

utf-8")

p = subprocess.popen(cmd,shell=true,stdout=-1,stderr=-1)

data = p.stdout.read()+p.stderr.read()

length =len(data)

len_data = struct.pack("i"

,length)

client.send(len_data)

print

(length)

client.send(data)

```#

# 2.自定義報頭解決粘包

具體思路:

傳送端:

1.先將所有的額外資訊打包到乙個頭中

2.然後先傳送頭部資料

3.最後傳送真實資料

接收端:

1.接收固定長度的頭部長度資料

2.根據長度資料獲取頭部資料

3.根據頭部資料獲取真實資料

### 客戶端

```python

import

socket

import

struct

import

json

c =socket.socket()

c.connect((

"127.0.0.1

",8888))

while

true:

cmd = input("

>>>:

").strip()

c.send(cmd.encode(

"utf-8"))

#頭部資料

data = c.recv(4)

head_length = struct.unpack("i"

,data)[0]

head_data = c.recv(head_length).decode("

utf-8")

head =json.loads(head_data)

print

(head)

#真實資料長度

data_length = head["

data_size"]

#接收真實資料

size =0

res = b""

while size temp = c.recv(1024)

size +=len(temp)

res +=temp

print(res.decode("

gbk"

))```

### 伺服器

```python

import

socket

import

subprocess

import

struct

import

json

server =socket.socket()

server.bind((

"127.0.0.1

",8888))

server.listen()

while

true:

client, addr =server.accept()

while

true:

cmd = client.recv(1024).decode("

utf-8")

p = subprocess.popen(cmd,shell=true,stdout=-1,stderr=-1)

#真實資料

data = p.stdout.read() +p.stderr.read()

#頭部資料

head =

head_data = json.dumps(head).encode("

utf-8")

#頭部長度

head_len = struct.pack("i"

,len(head_data))

#逐個傳送

client.send(head_len)

client.send(head_data)

client.send(data)

```

Socket粘包問題

這兩天看csdn有一些關於socket粘包,socket緩衝區設定的問題,發現自己不是很清楚,所以查資料了解記錄一下 一兩個簡單概念長連線與短連線 1.長連線 client方與server方先建立通訊連線,連線建立後不斷開,然後再進行報文傳送和接收。2.短連線 client方與server每進行一次...

Socket粘包問題

這兩天看csdn有一些關於socket粘包,socket緩衝區設定的問題,發現自己不是很清楚,所以查資料了解記錄一下 一兩個簡單概念長連線與短連線 1.長連線 client方與server方先建立通訊連線,連線建立後不斷開,然後再進行報文傳送和接收。2.短連線 client方與server每進行一次...

tcp粘包問題

什麼是粘包問題 粘包問題的起因是socket的快取機制。簡而言之 粘包問題就是如何將連續的資料按照不同的資料幀截斷,以及如何處理殘包情況。分割資料需要按需分配。處理殘包也很簡單 等 等它發來下一包資料,不管他發來多少資料,先拿來512,接到上次那512後面。湊成完整的資料幀。當然也有可能你發現這次來...