日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

粘包现象

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

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

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

shell=True,

stderr=subprocess.PIPE,

stdout=subprocess.PIPE)

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

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

?

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

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

tcp為提高傳輸效率,tcp優(yōu)化算法會把一些數(shù)據(jù)合成一個tcp段后一次發(fā)送出去,這樣接收方就收到了粘包數(shù)據(jù)

?

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

而udp發(fā)送數(shù)據(jù),對端是不會返回確認信息的,因此不可靠

?

使用tcp協(xié)議遠程執(zhí)行命令

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,在運行時會發(fā)生粘包

?

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

?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,在運行時永遠不會發(fā)生粘包

?

?

?

?

?

?

解決粘包的辦法

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

?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'))

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

?

海峰老師解決粘包的方法

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

?

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

總結

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。