粘包:

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模块,粘包解决终极大招的更多相关文章

  1. 2、粘包现象(struct模块)

    昨天我们所做的套接字是有漏洞的,它会出现粘包现象,没有发现这个问题的我们今天会进行演示.今天也会稍微讲解一下基于udp的套接字. 一.基于udp的套接字 udp是无链接的,先启动哪一端都不会报错 ud ...

  2. 29、粘包现象(struct模块)

    昨天我们所做的套接字是有漏洞的,它会出现粘包现象,没有发现这个问题的我们今天会进行演示.今天也会稍微讲解一下基于udp的套接字. 本篇导航: 基于udp的套接字 粘包现象 粘包 解决粘包方法 stru ...

  3. socker通信-struct模块-粘包问题

    Socket概念 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对 ...

  4. 黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论 _

    目录 黏包现象 二.struct模块及解决黏包问题的流程 三.粘包代码实战 UDP协议(了解) 并发编程理论 多道技术 进程理论 进程的并行与并发 进程的三状态 黏包现象 什么是粘包 1.服务端连续执 ...

  5. 11月17日内容总结——黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论

    目录 一.黏包现象 什么是黏包 黏包现象产生的原因 二.struct模块及解决黏包问题的流程 struct模块 解决黏包问题初级版本 解决过程中遇到的问题 解决黏包问题终极解决方案 三.粘包代码实战 ...

  6. struct模块-黏包的解决方法

    黏包的解决方案 解决方案一 问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死 ...

  7. 2、网络并发编程--套接字编程、黏包问题、struct模块、制作简易报头、上传文件数据

    昨日内容回顾 面向对象复习(json序列化类) 对象.类.父类的概念 三大特性:封装 继承 多态 双下开头的方法(达到某个条件自动触发) __init__:对象实例化自动触发 __str__:对象执行 ...

  8. 黏包现象、struct模块、并行与并发

    1.黏包现象 1.黏包现象产生的背景: 1.1 服务端连续执行三次recv 1.2 客户端连续执行三次send 执行上述操作会发现服务端一次性接收到了客户端三条消息,而后面两次什么都没接收到,该现象称 ...

  9. SpringBoot包扫描之多模块多包名扫描和同类名扫描冲突解决

    前言 我们在开发springboot项目时候,创建好SpringBoot项目就可以通过启动类直间启动,运行一个web项目,非常方便简单,不像我们之前通过Spring+SpringMvc要运行启动一个w ...

  10. 网络编程 --- subprocess模块,struct模块,粘包,UDP协议,socket_server模块

    目录 subprocess模块 struct模块 粘包 UDP协议 socket_server模块 subprocess模块 作用: 1.可以帮你通过代码执行操作系统的终端命令 2.并返回终端执行命令 ...

随机推荐

  1. Python爬虫之Scrapy制作爬虫

    前几天我有用过Scrapy架构编写了一篇爬虫的代码案例深受各位朋友们喜欢,今天趁着热乎在上一篇有关Scrapy制作的爬虫代码,相信有些基础的程序员应该能看的懂,很简单,废话不多说一起来看看. 前期准备 ...

  2. reactnative安装

    React Native 介绍 React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是React 在原生移动应用平台的衍生产物,使用JS.JSX.CS ...

  3. oracle中的merge into用法解析

    一:merge into的形式 MERGE INTO [target-table] A USING [source-table sql] B ON([conditional expression] a ...

  4. SQL Server 分页问题

    ------------- SQL Server 1.使用row_number分页 declare @PageSize int = 5 declare @PageIndex int = 1 selec ...

  5. C# 动态操作 控件位置绑定 [ Anchor ] 属性

    注: 1.此类属于非常用类,只因本人需要编写的...顺便刷贴一下 2.对于初学,其中的枚举使用可以为你加深一点印象 以下为操作类代码: public class AchCtrer { #region ...

  6. form表单 css的选择器和一些属性以及盒子模型,浮动

    form表单 <form action='' method='' enctype=''> <input type='text'> input:更下type属性就可以得到对应的效 ...

  7. 01 ansible的基本介绍

    1.现有的企业服务器环境 在现在的企业中,特别是互联网公司,他们的业务量众多:比如负载均衡服务器.web服务器.动态解析(php)服务器.数据库(mysql)服务器以及网站缓存服务器,等等: 例如:一 ...

  8. XML元素限定

    XML元素限定的意义:XML 用于数据交换,而标签又是可以任意定义的,为了让 XML 的编写者和使用者之间能正确交流----->需要对标签等约定.在 XML 中有两种约定方法 dtd 格式和 x ...

  9. CH9141进阶应用篇

    在基础篇中主要将的是主从连接透传数据,这也是CH9141模块的主要功能,这边呢就主要讲讲除了透传之外的功能, 如通用GPIO,ADC采集功能,串口配置功能. 这些功能均有两种实现方式,一种是通过AT指 ...

  10. 阿里云CentOS7 下部属nginx+uwsgi+python3+django

    安装依赖包 yum -y groupinstall "Development tools" yum install openssl-devel bzip2-devel expat- ...