日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

粘包现象

發布時間:2025/7/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 粘包现象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

讓我們基于tcp先制作一個遠程執行命令的程序

res=subprocess.Popen(cmd.decode('utf-8'),

shell=True,

stderr=subprocess.PIPE,

stdout=subprocess.PIPE)

的結果編碼是以當前所在的系統為準的,如果是windows,那么res.stdout.read()獨處的就是GBK編碼的,在接收端需要用GBK編碼

且只能從管道里讀一次結果

?

只有TCP有粘包現象,udp永遠你不會粘包,? tcp協議是面向流的協議, udp是面向消息的協議

所謂粘包的問題主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少個字節的數據所造成的

tcp為提高傳輸效率,tcp優化算法會把一些數據合成一個tcp段后一次發送出去,這樣接收方就收到了粘包數據

?

tcp在數據傳輸時,發送端先把數據發送到自己的緩存中,然后協議控制將緩存中的數據發往對端,對端返回一個ack=1,發送端則清理緩存中的數據,對端返回ack=0,則重新發送數據,所以tcp是可靠的

而udp發送數據,對端是不會返回確認信息的,因此不可靠

?

使用tcp協議遠程執行命令

from socket import *

import subprocess

?

ip_port=('127.0.0.1',8080)
BUFSIZE=1024

?

tcp_socket_server=socket(AF_INET,SOCK_STREAM)

tcp_socket_server.bind(ip_port)

tcp_socket_server.listen(5)

?

while True:

?

? ? conn,addr=tcp_socket_server.accept()

? ? print('客戶端‘,addr)

? ??

? ? while True:

? ? ? ? cmd=conn.recv(BUFSIZE)

? ? ? ? if len(cmd) == 0:break

? ?

? ? ? ? res = subprocess.Popen(cmd.decode('utf-8'),shell=True,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?stdout=subprocess.PIPE,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?stdin=subprocess.PIPE,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? stderr=subprocess.PIPE)? ? ? ?

? ? ? stderr=res.stderr.read()

? ? ? stdout=res.stdout.read()

? ? ? ?conn,send(stderr)

? ? ? ?conn,send(stdout)

?

客戶端

import socket

BUFSIZE=1024

ip_port=('127.0.0.1',8080)

?

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

res=s.connect_ex(ip_port)

?

while True:

? ? msg=input('>>:').strip()

? ? if len(msg) == 0:break

?

? ? s.send(msg.encode('utf-8'))

? ? act_res=s.recv(BUFSIZE)

?

? ? print(act_res.decode('utf-8'),end=")

上述程序基于tcp的socket,在運行時會發生粘包

?

小面基于udp制作一個遠程執行命令的程序

?from socket import *

import subprocess

?

ip_port=('127.0.0.1',8080)

bufsize=1024

?

udp_server=socket(AF_INET,SOCK=DGRAM)

udp_server.bind(ip_port)

?

while True:

? ? cmd,addr=udp_server.recvfrom(bufsize)

? ? print('用戶命令’,cmd)

? ??

? ? res=subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=subpross.PIPE,stdout=subprocess.PIPE)

? ? stderr=res.stderr.read()

? ? stdout=res.stdout.read()

?

? ? udp_server.sendto(stderr,addr)

? ? udp_server.sendto(stdout,addr)

udp_server.close()

客戶端

from socket import *

ip_port=('127.0.0.1',8080)

bufsize=1024

?

udp_client=socket(AF_INET,SOCK_DGRAM)

?

while True:

? ? msg=input('>>: ').strip()

? ? udp_client.sendto(msg.encode('utf-8'),ip_port)

?

? ? data,addr=udp_client.recvfrom(bufsize)

? ? print(data.decode('utf-8'),end=")

以上基于udp的socket,在運行時永遠不會發生粘包

?

?

?

?

?

?

解決粘包的辦法

問題的根源在于,接收端不知道發送端要傳送的字節流的長度,所以解決粘包的辦法就是圍繞如何讓發送端在發送數據前,把自己將要發送的字節流總大小讓接收端知曉,然后接收端來一個死循環接受完所有數據

?low版解決方法

from socket import *

import subprocess

ip_port=('127.0.0.1',8080)

s=socket(AF_INET,SOCK.STREAM)

s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)

?

s.bind(ip_port)

s.listen(5)

?

while True:

? ? conn,addr=s.accept()

? ? print('客戶端‘,addr)

? ? while True:

? ? ? ? msg=conn.recv(1024)

? ? ? ? if not msg:break

? ? ? ? res=subprocess.Popen(msg.decode('utf-8'),shell=True,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?stdin=subprocess.PIPE,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?stdout=subprocess.PIPE,

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?stderr=subprocess.PIPE)

? ? ? ? ? ?err=res.stderr.read()

? ? ? ? ? ?if err:

? ? ? ? ? ? ? ? ? ret=err

? ? ? ? ? ?else:

? ? ? ? ? ? ? ? ret=res.stdout.read()

? ? ? ? ? ?data_length=len(ret)

? ? ? ? ? ? conn.send(str(data_lenth).encode('utf-8'))

? ? ? ? ? ? data=conn.recv(1024).decode('utf-8')

? ? ? ? ? ? if data == 'recv_ready'

? ? ? ? ? ? ? ? ? ? conn.sendall(ret)

? ? ? ? conn.close()

客戶端

import socket,time

s=scoket.socket(socket.AF_INET,socket.SOCK.STRAM)

res=s.connect_ex(('127.0.0.1',8080))

?

while True:

? ? msg=input('>>:').strip()

? ? if len(msg) ==0:break

? ? if msg == 'quit':break

?

? ? s.send(msg.encode('utf-8'))

? ? length=int(s.recv(1024).decode('utf-8'))\

? ? s.send('recv_ready'.encode('utf-8'))

? ? send_size=0

? ? recv_size=0

? ? data=b''

? ? while recv_size <length:

? ? ? ? ? ? data+=s.recv(1024)

? ? ? ? ? ? recv_size+=len(data)

?

print(data.deode('utf-8'))

程序運行速度遠快于網絡傳輸速度,所以在發送一段字節前,先用send去發送該字節流長度,這種方式會放大網絡延遲帶來的性能損耗

?

海峰老師解決粘包的方法

為字節流加上自定義固定長度報頭,報頭中包含字節流長度,然后一次send到對端,對端在接受時,先從緩存中取出定長的報頭,然后再取真實數據

?

轉載于:https://www.cnblogs.com/mayicai/p/9220958.html

總結

以上是生活随笔為你收集整理的粘包现象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。