粘包,自定义协议,struct模块,粘包解决终极大招
粘包:
1.粘包问题出现的原因: (udp不会出现粘包问题)
1.1.tcp是流式协议,数据像水流一样黏在一起,没有任何边界区分
1.2.收数据没收干净,有残留,就会下一次结果混淆在一起去(客户端接受限制,发送端数据量太大)
2.解决粘包问题思路:
1.当时短连接的情况下,不用考虑粘包的情况
2.如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
3.如果双方建立长连接,需要在连接后一段时间内发送不同结构数据
3.1发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
3.2发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
3.3可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
struct模块:
import struct
# info = b'hello big baby'
# print(len(info)) # 数据真实的长度(bytes) 14
# res = struct.pack('i', len(info)) # 将数据打包成固定的长度 i是固定的打包模式
# print(len(res)) # 打包之后长度为(bytes) 4 报头
# real_len = struct.unpack('i', res)
# print(real_len) # (14,) 根据固定长度的报头 解析出真实数据的长度
# desc = b'hello my baby I will take you to play big ball'
# print(len(desc)) # 数据真实的长度(bytes) 46
# res1 = struct.pack('i', len(desc))
# print(len(res1)) # 打包之后长度为(bytes) 4 报头
# real_len1 = struct.unpack('i', res1)
# print(real_len1) # (46,) 根据固定长度的报头 解析出真实数据的长度
服务端:
'''终极解决方案:字典作为报头打包 效果更好 数字更小'''
import socket
import subprocess #Popen(子进程的创建和管理都靠他处理)
import struct
phone = socket.socket() #默认TCP协议
phone.bind(('127.0.0.1',8080)) #绑定ip加端口
phone.listen(5) #半连接池大小
while True:
conn,client_addr = phone.accept() #conn为三次握手的双向通路,client_addr为ip+端口
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0:break
obj = subprocess.Popen(cmd.decode('gbk'), #shell命令,可以是字符串或者序列类型(list,元组)
shell=True, #如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
stdout=subprocess.PIPE, #输出
stderr=subprocess.PIPE #错误句柄
)
stdout_res = obj.stdout.read()
stderr_res = obj.stderr.read()
total_size = len(stdout_res) + len(stderr_res)
#先发头部信息(固定长度的bytes):对数据描述的信息
#int-->固定长度的bytes
header = struct.pack('i',total_size) #按照指定格式将字节流转换为Python指定的数据类型(pick为字符串类型),短的用i,长的用Q
conn.send(header)
#再发真实数据
conn.send(stdout_res)
conn.send(stderr_res)
except Exception:
break
conn.close()
客户端:
import socket
import struct
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议--> tcp协议
client.connect(('127.0.0.1',8080)) #进行3次握手
while True:
msg = input('输入要发送的消息:').strip()
if len(msg) == 0:continue #解决输入空格的bug
client.send(msg.encode('utf8')) #编码以二进制的形式发送
#解决粘包问题的思路
# 2.1:先收固定长度的头:解析出数据的描述信息,包括数据的总大小total_size
header = client.recv(4) #如果是Q的话就是8
# total_size = xxxx
total_size = struct.unpack('i',header)[0] #解包
# recv_size = 0,循环接受,每接受一次,recv_size+=接受的长度
recv_size = 0
# 直到recv_size = total_size,结束循环
while recv_size < total_size:
recv_data = client.recv(1024)
recv_size+=len(recv_data)
print(recv_data.decode('gbk'),end='')
print('')
client.close()
解决粘包的终极大招:
################################模板
服务端:
#解决粘包问题终极版
import socket
import subprocess #Popen(子进程的创建和管理都靠他处理)
import struct
import json
phone = socket.socket() #默认TCP协议
phone.bind(('127.0.0.1',8081)) #绑定ip加端口
phone.listen(5) #半连接池大小
while True:
conn,client_addr = phone.accept() #conn为三次握手的双向通路,client_addr为ip+端口
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0:break
obj = subprocess.Popen(cmd.decode('gbk'), #shell命令,可以是字符串或者序列类型(list,元组)
shell=True, #如果该参数为 True,将通过操作系统的 shell 执行指定的命令。
stdout=subprocess.PIPE, #输出
stderr=subprocess.PIPE #错误句柄
)
stdout_res = obj.stdout.read()
stderr_res = obj.stderr.read()
total_size = len(stdout_res) + len(stderr_res)
#1.制作头部
header_dic = {
'filename':'a.txt', #文件名称
'total_size':total_size, #文件长度
'md5':'21561adas61d6'
}
json_str = json.dumps(header_dic) #数据类型转成字符串
json_str_bytes = json_str.encode('gbk') #字符串转成二进制
#2.先发头部信息(固定长度的bytes):对数据描述的信息
#int-->固定长度的bytes
header = struct.pack('i',len(json_str_bytes)) #按照指定格式将字节流转换为Python指定的数据类型(pick为字符串类型),短的用i,长的用Q
conn.send(header) #发送头的长度 4个字节
#3.发头信息
conn.send(json_str_bytes)
#再发真实数据
conn.send(stdout_res)
conn.send(stderr_res)
except Exception:
break
conn.close()
客户端:
#解决粘包问题终极版
import socket
import struct
import json
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式协议--> tcp协议
client.connect(('127.0.0.1',8081)) #进行3次握手
while True:
msg = input('输入要发送的消息:').strip()
if len(msg) == 0:continue #解决输入空格的bug
client.send(msg.encode('gbk')) #编码以二进制的形式发送
# 接收端
# 1.先收到4个字节,从中提取接下来头的长度
header = client.recv(4)
#2.接收头,并解析
header_len = struct.unpack('i',header)[0] #header_len为二进制的长度
json_str_bytes = client.recv(header_len) #接收
json_str = json_str_bytes.decode('gbk') #二进制转成字符串
header_dic = json.loads(json_str) #字符串转成数据类型
print(header_dic)
total_size = header_dic['total_size'] #得到头的长度
#接收真实的数据
recv_size = 0
# 直到recv_size = total_size,结束循环
while recv_size < total_size:
recv_data = client.recv(1024)
recv_size+=len(recv_data)
print(recv_data.decode('gbk'),end='')
print('')
client.close()
运行得到的结果为:
{'filename': 'a.txt', 'total_size': 65, 'md5': '21561adas61d6'}
'weqeqw' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
粘包,自定义协议,struct模块,粘包解决终极大招的更多相关文章
- 2、粘包现象(struct模块)
昨天我们所做的套接字是有漏洞的,它会出现粘包现象,没有发现这个问题的我们今天会进行演示.今天也会稍微讲解一下基于udp的套接字. 一.基于udp的套接字 udp是无链接的,先启动哪一端都不会报错 ud ...
- 29、粘包现象(struct模块)
昨天我们所做的套接字是有漏洞的,它会出现粘包现象,没有发现这个问题的我们今天会进行演示.今天也会稍微讲解一下基于udp的套接字. 本篇导航: 基于udp的套接字 粘包现象 粘包 解决粘包方法 stru ...
- socker通信-struct模块-粘包问题
Socket概念 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对 ...
- 黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论 _
目录 黏包现象 二.struct模块及解决黏包问题的流程 三.粘包代码实战 UDP协议(了解) 并发编程理论 多道技术 进程理论 进程的并行与并发 进程的三状态 黏包现象 什么是粘包 1.服务端连续执 ...
- 11月17日内容总结——黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论
目录 一.黏包现象 什么是黏包 黏包现象产生的原因 二.struct模块及解决黏包问题的流程 struct模块 解决黏包问题初级版本 解决过程中遇到的问题 解决黏包问题终极解决方案 三.粘包代码实战 ...
- struct模块-黏包的解决方法
黏包的解决方案 解决方案一 问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死 ...
- 2、网络并发编程--套接字编程、黏包问题、struct模块、制作简易报头、上传文件数据
昨日内容回顾 面向对象复习(json序列化类) 对象.类.父类的概念 三大特性:封装 继承 多态 双下开头的方法(达到某个条件自动触发) __init__:对象实例化自动触发 __str__:对象执行 ...
- 黏包现象、struct模块、并行与并发
1.黏包现象 1.黏包现象产生的背景: 1.1 服务端连续执行三次recv 1.2 客户端连续执行三次send 执行上述操作会发现服务端一次性接收到了客户端三条消息,而后面两次什么都没接收到,该现象称 ...
- SpringBoot包扫描之多模块多包名扫描和同类名扫描冲突解决
前言 我们在开发springboot项目时候,创建好SpringBoot项目就可以通过启动类直间启动,运行一个web项目,非常方便简单,不像我们之前通过Spring+SpringMvc要运行启动一个w ...
- 网络编程 --- subprocess模块,struct模块,粘包,UDP协议,socket_server模块
目录 subprocess模块 struct模块 粘包 UDP协议 socket_server模块 subprocess模块 作用: 1.可以帮你通过代码执行操作系统的终端命令 2.并返回终端执行命令 ...
随机推荐
- Elasticsearch 查询小笔记
2.x 版本,组合多查询https://www.elastic.co/guide/cn/elasticsearch/guide/current/combining-queries-together.h ...
- C#发送字符串转字节含空格与0x需删去
主要作用:清除发送字符串转字节中的空格和16进制前缀0x, 字节转换按两位字符转换为一个字节,多余一位按一位字符转换一个字节 //清除空格和16进制前缀发送 String sendstr;// = n ...
- Maven-高级
Mvaen 高级 1 导入其他工程 资源文件 先install到仓库里 然后根据组织名项目名版本号写在dependence里正常导入 <dependence> <groupId> ...
- 用requests库的get( )函数访问搜狗网站20次
代码: import requests from bs4 import BeautifulSoup def getHTMLText(url): try: r=requests.get(url,time ...
- 关于vmwork中centos7的虚拟机创建
1.准备vmwork软件和centos7的镜像文件 vmwork软件下载地址https://www.vmware.com/cn/products/workstation-pro/workstation ...
- CH573 CH582 CH579蓝牙从机(peripheral)例程讲解二(广播内容修改)
在上一篇外设例程讲解中讲述了蓝牙从机的收发接口,这样可以快速的上手,那么接下来就讲解另一个重要设置,从机的广播. 在peripheral例程中,一直是以50ms的周期进行广播,使用手机软件扫描可以获取 ...
- 转贴:阿里云ESC-centos7服务器小白搭建FTP教程
1. 安装vsftpd yum -y install vsftpd 2. 检查vsftpd是否安装成功 rpm -q vsftpd vsftpd-3.0.2-29.el7_9.x86_64 # 检查方 ...
- enobj.cn站有更新
1:整体样式 2:可以折叠app列表 3:手机端样式 4: Blog链接到博客园
- github相关操作
github里面有很多大神写的代码,但是有不少小伙伴对使用它比较的生疏,下面我就把它的简单和常规的操作说一下,希望对你查看github有一定的帮助. watch :会持续收到该项目的动态 fork : ...
- 迁移学习(CDAN)《Conditional Adversarial Domain Adaptation》(已复现迁移)
论文信息 论文标题:Conditional Adversarial Domain Adaptation论文作者:Yaroslav Ganin, Evgeniya Ustinova, Hana Ajak ...