python-day30--粘包

一、 什么是粘包

1.须知:只有TCP有粘包现象,UDP永远不会粘包

2.所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

二、两种情况下会发生粘包。

1.发送数据时间间隔很短,数据了很小,会合到一起,产生粘包

1 from socket import *
2 import time
3 phone=socket(AF_INET,SOCK_STREAM)
4 phone.connect(('127.0.0.1',8080))
5 
6 phone.send('helloworld'.encode('utf-8'))
7 phone.send('egon'.encode('utf-8'))
客户端

 

2.接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

from socket import *
import time
phone=socket(AF_INET,SOCK_STREAM)
phone.connect(('127.0.0.1',8080))

phone.send('helloworld'.encode('utf-8'))
time.sleep(5)
phone.send('egon'.encode('utf-8'))
客户端
from socket import *
phone=socket(AF_INET,SOCK_STREAM)
phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8080))
phone.listen(5)
conn,client_addr=phone.accept()

data1=conn.recv(8)
print('data1: ',data1)
data2=conn.recv(20)
print('data2:',data2)
data3=conn.recv(20)
print('data3:',data3)
# 结果
# data1:  b'hellowor'
# data2: b'ld'
# data3: b'egon'
服务端

三、

拆包的发生情况

当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。

补充问题一:为何tcp是可靠传输,udp是不可靠传输

基于tcp的数据传输请参考我的另一篇文章http://www.cnblogs.com/linhaifeng/articles/5937962.html,tcp在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据,所以tcp是可靠的

而udp发送数据,对端是不会返回确认信息的,因此不可靠

补充问题二:send(字节流)和recv(1024)及sendall

recv里指定的1024意思是从缓存里一次拿出1024个字节的数据

send的字节流是先放入己端缓存,然后由协议控制将缓存内容发往对端,如果待发送的字节流大小大于缓存剩余空间,那么数据丢失,用sendall就会循环调用send,数据不会丢失

四、解决粘包的low比处理方法

 1 import socket
 2 import subprocess
 3 import struct
 4 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
 5 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
 6 phone.bind(('127.0.0.1',8082)) #绑定手机卡
 7 phone.listen(5) #开机
 8 
 9 print('starting...')
10 while True: #链接循环
11     conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
12     print('-------->',conn,client_addr)
13     #收,发消息
14     while True:#通信循环
15         try:
16             cmd=conn.recv(1024)
17             if not cmd:break #针对linux
18             #执行cmd命令,拿到cmd的结果,结果应该是bytes类型
19             #。。。。
20             res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
21                                    stdout=subprocess.PIPE,
22                                    stderr=subprocess.PIPE)
23             stdout=res.stdout.read()
24             stderr=res.stderr.read()
25             #先发报头(转成固定长度的bytes类型)
26             header = struct.pack('i',len(stdout)+len(stderr))
27             conn.send(header)
28             #再发送命令的结果5
29             conn.send(stdout)
30             conn.send(stderr)
31         except Exception:
32             break
33     conn.close() #挂电话
34 phone.close() #关机
服务端
 1 import socket
 2 import struct
 3 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
 4 phone.connect(('127.0.0.1',8082)) #绑定手机卡
 5 #发,收消息
 6 while True:
 7     cmd=input('>>: ').strip()
 8     if not cmd:continue
 9     phone.send(cmd.encode('utf-8'))
10     #先收报头
11     header_struct=phone.recv(4)
12     unpack_res = struct.unpack('i', header_struct)
13     total_size=unpack_res[0]
14     #再收数据
15     recv_size=0 #10241=10240+1
16     total_data=b''
17     while recv_size < total_size:
18         recv_data=phone.recv(1024)
19         recv_size+=len(recv_data)
20         total_data+=recv_data
21     print(total_data.decode('gbk'))
22 phone.close()
客户端

 五、完美解决tcp协议粘包问题

 1 import socket
 2 import subprocess
 3 import struct
 4 import json
 5 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
 6 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加
 7 phone.bind(('127.0.0.1',8082)) #绑定手机卡
 8 phone.listen(5) #开机
 9 
10 print('starting...')
11 while True: #链接循环
12     conn,client_addr=phone.accept() #等电话 (链接,客户的的ip和端口组成的元组)
13     print('-------->',conn,client_addr)
14 
15     #收,发消息
16     while True:#通信循环
17         try:
18             cmd=conn.recv(1024)
19             if not cmd:break #针对linux
20             #执行cmd命令,拿到cmd的结果,结果应该是bytes类型
21             #。。。。
22             res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
23                                    stdout=subprocess.PIPE,
24                                    stderr=subprocess.PIPE)
25             stdout=res.stdout.read()
26             stderr=res.stderr.read()
27             #制作报头
28             header_dic = {
29                 'total_size': len(stdout)+len(stderr),
30                 'filename': None,
31                 'md5': None}
32 
33             header_json = json.dumps(header_dic)
34             header_bytes = header_json.encode('utf-8')
35             #发送阶段
36             #先发报头长度
37             conn.send(struct.pack('i',len(header_bytes)))
38             #再发报头
39             conn.send(header_bytes)
40 
41             #最后发送命令的结果
42             conn.send(stdout)
43             conn.send(stderr)
44         except Exception:
45             break
46     conn.close() #挂电话
47 phone.close() #关机
服务端
 1 import socket
 2 import struct
 3 import json
 4 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #买手机
 5 phone.connect(('127.0.0.1',8082)) #绑定手机卡
 6 
 7 #发,收消息
 8 while True:
 9     cmd=input('>>: ').strip()
10     if not cmd:continue
11 
12     phone.send(cmd.encode('utf-8'))
13     #先收报头的长度
14     header_len=struct.unpack('i',phone.recv(4))[0]
15 
16     #再收报头
17     header_bytes=phone.recv(header_len)
18     header_json=header_bytes.decode('utf-8')
19     header_dic=json.loads(header_json)
20     total_size=header_dic['total_size']
21 
22     #最后收数据
23     recv_size=0 #10241=10240+1
24     total_data=b''
25     while recv_size < total_size:
26         recv_data=phone.recv(1024)
27         recv_size+=len(recv_data)
28         total_data+=recv_data
29     print(total_data.decode('gbk'))
30 phone.close()
客户端

 

转载于:https://www.cnblogs.com/liuwei0824/p/7413463.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
python-UDP是指在Python编程语言中使用UDP协议进行网络通信。UDP是一种无连接的传输层协议,不需要建立连接即可发送和接收数据。与TCP相比,UDP的效率更高,但也不可靠,容易丢失数据。使用UDP的常见服务有DNS和FTP等。在Python中,可以使用socketserver模块实现UDP传输协议的并发通信。通过创建UDP报头并指定接收端的IP和端口信息,可以使用sendto()方法发送数据,recvfrom()方法接收数据。在使用recvfrom()方法时,它是阻塞的,每次接收一定数量的数据,若发送的数据超过接收的数量,就会丢失数据。因此,UDP不会出现数据的情况,但也需要注意数据的丢失问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python-UDP协议](https://blog.csdn.net/qq_48985780/article/details/121877448)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python - UDP通信](https://blog.csdn.net/weixin_39940253/article/details/110761121)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值