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其实就是一个门面模 ...
随机推荐
- linux 存取 I/O 内存
在一些平台上, 你可能逃过作为一个指针使用 ioremap 的返回值的惩罚. 这样的使用不 是可移植的, 并且, 更加地, 内核开发者已经努力来消除任何这样的使用. 使用 I/O 内 存的正确方式是通 ...
- JUnit 单元测试断言推荐 AssertJ
文章转自:http://sgq0085.iteye.com/blog/2030609 前言 由于JUnit的Assert是公认的烂API,所以不推荐使用,目前推荐使用的是AssertJ. Assert ...
- vue-learning:25 - component - 概念-定义-注册-使用-命名
概念 Vue遵循Web Component规范,提供了自己的组件系统.组件是一段独立的代码,代表页面中某个功能块,拥有自己的数据.JS.样式,以及标签.组件的独立性是指形成自己独立的作用域,不会对其它 ...
- 抓取IOS的apsd进程流量
IOS的apsd是Apple Push Service的相关进程,很多系统服务都跟他有关,比如iMessage.Homekit,因此想抓包查看他是怎么实现的. 1.搜索发现相关资料很少,只有多年前的一 ...
- PostgreSQL 遇到 column "value" does not exist
初次使用PostgreSQL,在执行插入语句的时候死活插入不进去数据 INSERT INTO pre_trait ( archive_id, apply_from, owner_area_code ) ...
- C++中常量成员函数的含义
C++中常量成员函数的含义 本文内容来源:<C++必知必会> 使用常量成员函数可以改变对象的逻辑状态,虽然对象的物理状态没有发生改变.考虑如下代码,它定义了一个类X: class X{ p ...
- git之github推送篇
1.创建项目 2.生成ssh密钥并设置到github 在文件夹里面右键打开git命令行,输入下面命令,然后一直回车. ssh-keygen -t rsa 生成位置在当前用户的.ssh文件夹里,带pu ...
- js中时间戳转换成xxxx-xx-xx xx:xx:xx类型日期格式的做法
1.十三位数字的时间戳转换方法 var time = new Date(datetime).toLocaleString().replace(/年|月/g, "-").replac ...
- $loj6043$ [雅礼集训 $2017\ Day7$] 蛐蛐国的修墙方案 搜索
正解:搜索 解题报告: 传送门$QwQ$ 首先由$p_i$是一个序列得,每个点的度数为2.且一定形成若干个环. 考虑先对每个环做,发现若要有解必须是偶环,且一定是隔一条边选一条边的,所以对每个环其实只 ...
- 机器学习之路--Matplotlib
1.绘制折线图 在pandas里面有一种数据类型为datatime ,可以将不规范的日期改为:xxxx-xx-xx import pandas as pd import numpy as np a = ...