python 黏包现象
一、黏包
1、tcp有黏包现象
表现两种情况
发送的数据过小且下面还有一个发送数据,这两个数据会一起发送
发送的数据过大,超过最大缓存空间,超出的部分在下一次发送的时候发送
原因:
tcp是面向流的,根据算法,自动把数据拆分、组合,没有保护边界
2、udp无黏包现象
表现形式
发送的数据包大小超出最大缓存空间,超出的数据直接丢弃
udp不是面向流的,是面向消息的
总结
tcp协议是:可靠的,面向连接的,面向流的,效率低
udp协议是:不可靠的,无连接的,面向对象的,效率高
一般视频下载是tcp协议
聊天软件是udp协议
数据传输,传输的是数据包,数据包的内容是报文,报文有报头等
二、黏包现象
1、接连发生数据较小的数据包,且只接收数据一次
"""
Server端
在Client端接连发送两个小的数据包,Server端只有一个接收,且接收文件较大
会出现黏包现象
"""
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
ret = connect.recv(1024)
print(ret.decode('utf-8'))
connect.close()
sk.close()
"""
Client端
"""
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
sk.send('tom'.encode('utf-8'))
sk.send(' is god'.encode('utf-8'))
sk.close()
2、发送一个大的数据包,接收多次,且第一次接收的数据比较小
"""
Server端
在Client端发送一个数据包,Server端只接收两次,且第一次接受的数据较少
会出现黏包现象
"""
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
ret1 = connect.recv(4).decode('utf-8')
ret2 = connect.recv(10).decode('utf-8')
print(ret1)
print(ret2)
connect.close()
sk.close()
"""
Client端
"""
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
sk.send('tom is god'.encode('utf-8'))
sk.close()
示例
"""
Server端
向Client端发送cmd命令,利用subprocess,执行命令并且发送两次
发送黏包现象
"""
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
while 1:
cmd = input('>>>')
connect.send(cmd.encode('gbk'))
if cmd == 'q':
break
ret = connect.recv(1024).decode('gbk')
print(ret)
connect.close()
sk.close()
"""
Client端
"""
import socket
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
while 1:
cmd = sk.recv(1024).decode('gbk')
if cmd == 'q':
break
res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out = res.stdout.read() # bytes数据类型
std_error = res.stderr.read()
sk.send(std_out)
sk.send(std_error)
print(std_out.decode('gbk'))
print(std_error.decode('gbk'))
sk.close()
三、解决黏包
两种方法
1、预先知道发送端发送数据包的大小
2、使用struct变成固定大小的bytes类型
第一种方法,为了不产生黏包,每执行一次多产生一次网络延迟
"""
Server端
"""
import socket
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
while 1:
cmd = input('>>>')
connect.send(cmd.encode('utf-8'))
if cmd == 'q':
break
new_len = int(connect.recv(1024).decode('utf-8'))
connect.send(bytes('ok', 'utf-8'))
msg = connect.recv(new_len)
print(msg.decode('utf-8'))
connect.close()
sk.close()
"""
Client端
subprocess 产生的数据是bytes类型
计数bytes的长度->str
"""
import socket
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
while 1:
cmd = sk.recv(1024).decode('utf-8')
if cmd == 'q':
break
res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out = res.stdout.read()
std_err = res.stderr.read()
new_len = str(len(std_out + std_err))
sk.send(new_len.encode('utf-8'))
sk.recv(1024)
sk.send(std_out)
sk.send(std_err)
print(std_out.decode('utf-8'))
print(std_err.decode('utf-8'))
sk.close()
第二种方法使用struct
struct的应用
"""
'i'-> int
作用:把数字转换成固定4个字节的bytes类型
注意: unpack 时,要使用pack的返回值,unpack的是一个tuple,需要取第一个值
"""
import struct
a = struct.pack('i', 1234567)
print(a)
b = struct.unpack('i', a)[0]
print(b, type(b))
"""
b'\x87\xd6\x12\x00'
1234567 <class 'int'>
"""
解决黏包方法实现,每一次执行一次,对比上面的方法,少一次网络延迟
"""
Server端,接收pack的数据,unpack
"""
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
while 1:
cmd = input('>>>')
connect.send(cmd.encode('gbk'))
if cmd == 'q':
break
num = connect.recv(4)
b = struct.unpack('i', num)[0]
ret = connect.recv(b)
print(ret.decode('gbk'))
connect.close()
sk.close()
"""
Client端,将数据的长度pack,并传输
"""
import socket
import subprocess
import struct
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
while 1:
cmd = sk.recv(1024).decode('gbk')
if cmd == 'q':
break
res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out = res.stdout.read()
std_err = res.stderr.read()
new_len = len(std_out) + len(std_err)
res = struct.pack('i', new_len)
sk.send(res)
sk.send(std_out)
sk.send(std_err)
print(std_out.decode('gbk'))
print(std_err.decode('gbk'))
sk.close()
简单的文件下载
注意:文件的读写速度不一样,读的速度远大于写
"""
Server端
接收端
bytes->str->dict
"""
import socket
import struct
import json
buff = 1024
sk = socket.socket()
sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sk.bind(('127.0.0.1', 8010))
sk.listen()
connect, addr = sk.accept()
pack_len = connect.recv(4)
head_len = struct.unpack('i', pack_len)[0]
head_bytes = connect.recv(head_len)
head_str = head_bytes.decode('utf-8')
head = json.loads(head_str)
print(head)
file_size = head['file_size']
with open(file=head['filename'], mode='wb') as f:
while file_size:
if file_size >= buff:
context = connect.recv(buff)
f.write(context)
file_size -= buff
print(file_size)
else:
try:
context = connect.recv(file_size)
f.write(context)
except TypeError:
print('integer argument expected, got float')
break
connect.close()
sk.close()
"""
Client端
发送端
dict->str->bytes
"""
import socket
import os
import json
import struct
buff = 1024
sk = socket.socket()
sk.connect(('127.0.0.1', 8010))
# 设置文件报头,dict
head = {'filepath': r'D:\Temp', 'filename': r'test.mp4', 'file_size': None}
file_path = os.path.join(head['filepath'], head['filename'])
file_size = os.path.getmtime(file_path)
head['file_size'] = file_size
# dict ->str
head_str = json.dumps(head)
# str -> bytes
head_bytes = head_str.encode('utf-8')
# 将长度,转换成固定长度的bytes类型
pack_len = struct.pack('i', len(head_bytes))
sk.send(pack_len)
sk.send(head_bytes)
print(file_path)
with open(file=file_path, mode='rb') as f:
while file_size:
if file_size >= buff:
context = f.read(buff)
sk.send(context)
file_size -= buff
print(file_size)
else:
try:
context = f.read()
sk.send(context)
except TypeError:
print('integer argument expected, got float')
break
sk.close()
python 黏包现象的更多相关文章
- python 黏包现象及其解决方案
一.数据缓冲区 缓冲区(buffer),它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,显然缓冲区是具有一定大小的 ...
- python黏包现象
#黏包:发送端发送数据,接收端不知道应如何去接收造成的一种数据混乱现象. #关于分包和黏包: #黏包:发送端发送两个字符串"hello"和"word",接收方却 ...
- Python 之网络编程之socket(2)黏包现象和socketserver并发
一:黏包 ###tcp协议在发送数据时,会出现黏包现象. (1)数据粘包是因为在客户端/服务器端都会有一个数据缓冲区, 缓冲区用来临时保存数据,为了保证能够完整的接收到数据,因此缓冲区 ...
- python中黏包现象
#黏包:发送端发送数据,接收端不知道应如何去接收造成的一种数据混乱现象. #关于分包和黏包: #黏包:发送端发送两个字符串"hello"和"word",接收方却 ...
- Python网络编程基础 ❷ 基于upd的socket服务 TCP黏包现象
TCP的长连接 基于upd的socket服务 TCP黏包现象
- 黏包现象之TCP
老师的博客:http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 server #_*_coding:gbk*_ from socket ...
- 铁乐学Python_Day34_Socket模块2和黏包现象
铁乐学Python_Day34_Socket模块2和黏包现象 套接字 套接字是计算机网络数据结构,它体现了C/S结构中"通信端点"的概念. 在任何类型的通信开始之前,网络应用程序必 ...
- day28 1.缓冲区 2.subprocess 3.黏包现象 4.黏包现象解决方案 5.struct
1.缓冲区: 输入缓冲区 输出缓冲区 2. subprocess的使用import subprocess sub_obj = subprocess.Popen('ls', #系统指令shell=Tr ...
- socket套接字模块及黏包现象
一.socket套接字模块 socket概念 socket层 理解socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模 ...
随机推荐
- C# double 好用的扩展
在很多代码需要使用数学计算,在用到 double 很难直接判断一个值是 0 或者 1 ,判断两个值相等. 本文提供一个数学扩展,让大家可以简单使用到 double 判断 在开始看本文之前,希望大家是知 ...
- 中和IOS七层架构和TCP/IP四层架构的五层架构
五层架构分别为应用层.运输层.网络层.数据链路层.物理层. IOS架构把应用层又细分为应用层.表示层.会话层 TCP/IP把网络层改名网际层,数据链路层和物理层结合成网络接口层 其实只要学习五层协议, ...
- HDU 5912 Fraction(模拟)
Problem Description Mr. Frog recently studied how to add two fractions up, and he came up with an ev ...
- Linux 内核热插拔操作
热插拔事件的实际控制是通过一套存储于 kset_hotplug_ops 结构的方法完成. struct kset_hotplug_ops { int (*filter)(struct kset *ks ...
- dotnet core 集成到 Mattermost 聊天工具
在找了很久的团队交流工具,发现了 Mattermost 最好用,但是还需要做一些定制化的功能,于是就找到了 Mattermost 插件开发,还找到了如何自己写服务集成到 Mattermost 里面 本 ...
- 纯CSS制作空心三角形和实心三角形及其实现原理
纯CSS制作空心三角形和实心三角形及其实现原理 在一次项目中需要使用到空心三角形,我瞬间懵逼了.查阅了一些资料加上自己的分析思考,终于是达到了效果,个人感觉制作三角形是使用频率很高的,因此记录下来,供 ...
- dotnet 使用 Environment.FailFast 结束程序
在运行到一些诡异的代码,这时的程序已经无法继续运行,需要退出,那么如何在记完日志之后在退出程序记录更多信息?可以通过 Environment.FailFast 里面添加字符串告诉用户当前的进程无法继续 ...
- dotnet 通过 WMI 获取设备厂商
本文告诉大家如何通过 WMI 获取设备厂商 通过 Win32_ComputerSystem 可以获取电脑系统信息 通过下面代码可以获取 机器型号 和 制造厂商 var mc = "Win32 ...
- SPOJ VLATTICE (莫比乌斯反演)
传送门:https://www.spoj.com/problems/VLATTICE/en/ 题意: 在三维坐标系下,你在点(0,0,0),看的范围是(n,n,n)以内,求你可以看见多少个点没有被遮挡 ...
- freemarker<三>
前两篇博客介绍了freemaker是什么以及简单的语法规则,下面我们通过实现一个demo来看在实际应用中如何使用freemaker,本篇博客主要介绍freemaker与spring的整合. 需要的Ja ...