解決粘包現象

2022-05-04 17:06:09 字數 4863 閱讀 1480

簡單版

服務端

#

!/usr/bin/env python

#_*_ coding:utf-8 _*_

#author:mr.yang

import

socket

import

struct

import

subprocess

phone =socket.socket(socket.af_inet,socket.sock_stream)

phone.bind((

'127.0.0.1

',8080))

phone.listen(5)

print('

setting...')

while true: #

鏈結迴圈

conn,a =phone.accept()

while true: #

通訊迴圈

try:

#1.接收資料

data = conn.recv(8096)

print('

客戶端資料:

',data)

#2.執行命令,拿到結果

obj = subprocess.popen(data.decode('

utf-8

'), shell=true, #

shell 可以解析前面的字串,相當於cmd

stdout=subprocess.pipe, #

正確管道

stderr=subprocess.pipe) #

錯誤管道

stdout = obj.stdout.read() #

bytes型別

stderr =obj.stderr.read()

#3.將結果返回給客戶端

#第一步: 制定固定長度的報頭

total_size = len(stdout) +len(stderr)

header = struct.pack('i'

,total_size)

#第二步: 把報頭髮送給客戶端

conn.send(header)

#第三步: 在傳送真實的資料

conn.send(stdout)

conn.send(stderr)

#分開寫的原因,tcp會自動粘包,可以起到優化的作用

except

connectionreseterror:

break

conn.close

phone.close()

客戶端

#

!/usr/bin/env python

#_*_ coding:utf-8 _*_

#author:mr.yang

'''recv不能設定數值特別大的原因:

1.在接收檔案的時候可能超過指定數值

2.自己的作業系統的快取不能無限大,最大也不能超過作業系統的快取

'''import

socket,struct

phone =socket.socket(socket.af_inet,socket.sock_stream)

phone.connect((

'127.0.0.1

',8080))

while

true:

#1.發命令

cmd = input('

>>:

').strip()

ifnot cmd:continue

phone.send(cmd.encode(

'utf-8'))

#2.拿到命令結果

#第一步: 先收報頭

header = phone.recv(4)

#第二步: 從報頭中解析出對真實資料的描述資訊 (資料的長度)

tolal_size = struct.unpack('i'

,header)[0]

#第三步: 接收真實的資料

recv_size=0

recv_data=b''

while recv_size res = phone.recv(100)

recv_data +=res

recv_size +=len(res)

print(recv_data.decode('

gbk'

))phone.close()

終極版

服務端

#

!/usr/bin/env python

#_*_ coding:utf-8 _*_

#author:mr.yang

import

socket

import

struct

import

json

import

subprocess

'''相對於簡單版的優化

1.報頭資訊少

2.struct的i格式有限制

'''phone =socket.socket(socket.af_inet,socket.sock_stream)

phone.bind((

'127.0.0.1

',8080))

phone.listen(5)

print('

setting...')

while true: #

鏈結迴圈

conn,a =phone.accept()

while true: #

通訊迴圈

try:

#1.接收資料

data = conn.recv(8096)

print('

客戶端資料:

',data)

#2.執行命令,拿到結果

obj = subprocess.popen(data.decode('

utf-8

'), shell=true, #

shell 可以解析前面的字串,相當於cmd

stdout=subprocess.pipe, #

正確管道

stderr=subprocess.pipe) #

錯誤管道

stdout = obj.stdout.read() #

bytes型別

stderr =obj.stderr.read()

#3.將結果返回給客戶端

#第一步: 制定固定長度的報頭

header_dic=

header_json=json.dumps(header_dic)

header_bytes = header_json.encode('

utf-8')

#第二步:先發報頭的長度

conn.send(struct.pack('i'

,len(header_bytes)))

#第三步:再發報頭

conn.send(header_bytes)

#第四步: 在傳送真實的資料

conn.send(stdout)

conn.send(stderr)

#分開寫的原因,tcp會自動粘包

except

connectionreseterror:

break

conn.close

phone.close()

客戶端

#

!/usr/bin/env python

#_*_ coding:utf-8 _*_

#author:mr.yang

'''recv不能設定數值特別大的原因:

1.在接收檔案的時候可能超過指定數值

2.自己的作業系統的快取不能無限大,最大也不能超過作業系統的快取

'''import

socket

import

struct

import

json

phone =socket.socket(socket.af_inet,socket.sock_stream)

phone.connect((

'127.0.0.1

',8080))

while

true:

#1.發命令

cmd = input('

>>:

').strip()

ifnot cmd:continue

phone.send(cmd.encode(

'utf-8'))

#2.拿到命令結果

#第一步: 先收報頭的長度

obj = phone.recv(4)

header_size = struct.unpack('i'

,obj)[0]

#第二步: 再收報頭

header_bytes =phone.recv(header_size)

#第三步: 從報頭中解析出對真實資料的描述資訊

header_json = header_bytes.decode('

utf-8')

header_dic =json.loads(header_json)

print

(header_dic)

total_size = header_dic['

total_size']

#第四步: 接收真實的資料

recv_size=0

recv_data=b''

while recv_size res = phone.recv(1024)

recv_data +=res

recv_size +=len(res)

print(recv_data.decode('

gbk'

))phone.close()

tcp粘包現象

二 什麼時候需要考慮粘包問題?1 如果利用tcp每次傳送資料,就與對方建立連線,然後雙方傳送完一段資料後,就關閉連線,這樣就不會出現粘包問題 因為只有一種包結構,類似於http協議 關閉連線主要要雙方都傳送close連線 參考tcp關閉協議 如 a需要傳送一段字串給b,那麼a與b建立連線,然後傳送雙...

粘包現象與解決辦法

一 什麼是粘包現象 須知 只有tcp有粘包現象,udp永遠不會粘包 粘包不一定會發生,如果發生了 1.可能是在客戶端已經粘了,2.客戶端沒有粘,可能是在服務端粘了 粘包現象 tcp粘包是指傳送方傳送的若干包資料到接收方接收時粘成一包,從接收緩衝區看,後一包資料的頭緊接著前一包資料的尾。成因 所謂粘包...

粘包現象與解決方案

粘包是指兩次輸出結果粘到一起,它的發生主要是因為socket緩衝區導致的,粘包只在tcp中產生,不在udp產生 使用struct模組,先報頭長度進行打包發給客戶端,客戶端收到之後先解包報頭長度,再接收真實的資料 例子 服務端 usr bin env python3 coding utf 8 impo...