Python socket粘包问题(最终解决办法)
套接字:
	就是将传输层以下的协议封装成子接口
	对于应用程序来说只需调用套接字的接口,写出的程序自然是遵循tcp或udp协议的
实现第一个功能个:
实现:通过客户端向服务端发送命令,调取windows下面的cmd窗口,将服务端执行命令的结构,返回并显示在
	  客户端窗口上。
	subprocess:
		1.可以将执行结果返回
		2.返回值是bytes类型
		(基于这两点,可以应用在server端,将服务端的返回直接以bytes的格式直接send给客户端,
		 实现在客户端的显示)
问题1:粘包问题
		粘包问题:实际是由TCP协议在传输数据时的2大特性来的
			TCP协议又叫流式协议,在数据传输上,只要客户端发送相应的数据请求,
			服务端会将数据像流水一样不断的send给客户端
基于这个特点,就会存在一个问题,当客户端给服务端发送一条命令,服务端成功接收并将命令的
			结果返回到客户端的时候,由于客户端recv()的数量限制,可以一次不能完全取出,
			这个时候就会存在,下次输入命令客户端首先拿到的返回值就是上次残留的没有收完的数据
基于粘包问题的解决思路就是:
			发数据之前先把报头发给对方,让对方先知道要收的报头的长度,后面再传数据文件
自定义报头:
		为甚么要自定义报头:
		因为struck path(‘i’,3443242) 
		1.’i‘:类型不同,后面数字的长度大小也不同,大小是有限的(当超出范围时会报错)
		2.因为报头里面含有的内容可能不仅仅只有total_siz还有filename、hash等等,知识单纯的把total_size
		当做报头传入不合理,所以我们要自定义报头
Server端配置
from socket import *
import socket,subprocess,struct,json server = socket.socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8080))
server.listen(5) while True:
conn,client = server.accept()
print(client)
while True:
try:
cmd = conn.recv(1024)
if len(cmd) == 0: break
obj=subprocess.Popen(
cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE, )
out=obj.stdout.read()
err=obj.stderr.read() #制作报头
header_dic={
'filename':'a.txt',
'total_size':len(out)+len(err),
'hash':'abc32i5o24' }
#对包头进行序列化
header_json=json.dumps(header_dic) #字符串格式
header_bytes=header_json.encode('utf-8') #1.先发型报头的长度 len(header_bytes) struck为固定的4个字节
conn.send(struct.pack('i',len(header_bytes)))
#2.发送报头
conn.send(header_bytes)
#3.发送真是数据
conn.send(out)
conn.send(err) except ConnectionResetError:
break
conn.close() server.close()
Client端配置
from socket import *
import socket,struct,json
client=socket.socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))
while True:
cmd=input('输入你要操作的命令:')
client.send(cmd.encode('utf-8'))
if len(cmd) == 0:continue #1.先收报头的四个字节,首先拿到报头传来的长度-》bytes
header=client.recv(4) #i类型足够了 header为bytes类型
header_size=struct.unpack('i',header)[0] #拿到元祖形式,取第一个就是整个报头的长度
print(header_size) #为报头的长度值
#2.再收报头(对应服务端的conn.send(header_bytes))
header_bytes=client.recv(header_size) #根据报头的固定长度去收接收 #3.解析包头(就是将header_bytes文件先解码成json格式)
header_str=header_bytes.decode('utf-8')
header_dic=json.loads(header_str)
print(header_dic) total_size=header_dic['total_size']
print(total_size) recv_size=0 #定义一个初始的接收变量为0,只是个计数变量,为了统计与总的total_size的len大小
res=b''
while recv_size < total_size:
recv_data=client.recv(1024) #每次传过来的recv_data是bytes类型
res+=recv_data
recv_size+=len(recv_data) #循环增加每次接收值的长度 # cmd=client.recv(1024)
print(res.decode('gbk')) client.close()
粘包问题的最终解决方案,分析:
服务端:
目的为了自定义报头(报头中不仅包含长度,可能还有文件名等信息) subprocess
... 1.制作报头(字典形式)
header_dic={
'filename':'a.txt',
'total_size':len(out)+len(err),
'hash':'abc32i5o24' } 2.通过json将报头序列化再encode为bytes类型
header_json=json.dumps(header_dic) #字符串类型
header_bytes=header_json.encode('utf-8') #bytes类型 3.发送报头的长度,struck目的是固定封装好的报头为4个字节长度 =====对应客户端刚开始 header=client.recv(4)
struck: 1.将数字转为bytes类型,保证发送过去的是bytes类型 2.固定4个字节 第一次发:conn.send(struck.pack('i',len(header_bytes))) 先传给客户端固定了收的时候报头的长度,不至于报头和其他内容粘在一起 4.发送报头 =======对应客户端接收报头 header_bytes=client.recv(header_size)
第二次发:conn.send(header_bytes) 5.发送真实的数据
conn.send(out)
conn.send(err) 客户端:(bytes--int) 1.通过服务端返回的字节,拿到报头的的长度
header=client.recv(4) #header是4个bytes字节
header_size=struck.unpack('i',header)[0] #字节头-拿到int大小 2.再收报头
header_bytes=client.recv(header_size) #bytes类型 3.解析报头(1.先把内存中存放的bytes类型,用decode('utf-8')解码为字符串)
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json) #json反序列化出字典格式 (对应server第2步) print(header_dic) 4.拿到字典中的报头大小
total_size=header_dic['total_size']
print(total_size)
struck功能辅助理解:所以客户端刚开始接收4 大小是足够把报头接收完的。
#
struck工鞥理解:
import struct
#将整型转成bytes
res=struct.pack('i',1232435436)
print(res,len(res)) #res:为bytes类型,还是固定长度4(一般情况已经可以包含很多) #将bytes转成整型
aa=struct.unpack('i',res)
print(aa,aa[0],type(aa)) # print(len(res)) #4 一般情况多数bytes 4个长度足够了 """结果
b'\xecxuI' 4
(1232435436,) 1232435436 <class 'tuple'>
4
"""
Python socket粘包问题(最终解决办法)的更多相关文章
- Python socket粘包解决
		
socket粘包: socket 交互send时,连续处理多个send时会出现粘包,soket会把两条send作为一条send强制发送,会粘在一起. send发送会根据recv定义的数值发送一个固定的 ...
 - Python socket粘包问题(初级解决办法)
		
server端配置: import socket,subprocess,struct from socket import * server=socket(AF_INET,SOCK_STREAM) s ...
 - Python socket 粘包
		
目录 1 TCP的三次握手四次挥手 0 1.1 三次握手 1 1.2 四次挥手 2 2 粘包现象 3 2.1 基于TCP制作远程执行命令操作(win服务端) 4 2.1 基于TCP制作远程执行命令操作 ...
 - python socket粘包及实例
		
1.在linux中经常出现粘包的出现(因为两个send近靠着,造成接受到的数据是在一起的.)解决方法: 在服务端两send的中间中再添加一个recv(),客户端添加一个send(),服务端收到信息确认 ...
 - socket粘包现象加解决办法
		
socket粘包现象分析与解决方案 简单远程执行命令程序开发(内容回顾) res = subprocess.Popen(cmd.decode('utf-8'),shell=True,stderr=su ...
 - 百万年薪python之路  --  socket粘包问题解决
		
socket粘包问题解决 1. 高大上版解决粘包方式(自定制包头) 整体的流程解释 整个流程的大致解释: 我们可以把报头做成字典,字典里包含将要发送的真实数据的描述信息(大小啊之类的),然后json序 ...
 - Socket粘包问题
		
这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...
 - [转]关于Socket粘包问题
		
这两天看csdn有一些关于socket粘包,socket缓冲区设置的问题,发现自己不是很清楚,所以查资料了解记录一下: 一两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通 ...
 - Python之粘包
		
Python之粘包 让我们基于tcp先制作一个远程执行命令的程序(1:执行错误命令 2:执行ls 3:执行ifconfig) 注意注意注意: res=subprocess.Popen(cmd.deco ...
 
随机推荐
- 从零开始的Lua宅[1]:编译Lua解释器
			
Lua是一门神奇的脚本语言,游戏宅必备,懒人必备.Lua差多不是学起来用起来最简单的语言了,以至于简单到自身就是文档,自身就是配置文件.但是Lua的运行效率却是众多脚本中非常高的,据说仅次于V8爹下的 ...
 - ComboBox控件“设置 DataSource 属性后无法修改项集合”的解决【转】
			
编写Winform程序,遇到comboBox的绑定事件和索引项变更事件的冲突问题,就是“设置 DataSource 属性后无法修改项集合”的错误问题,网上查了很多,大多说在索引项变更是进行非空判断,还 ...
 - SAP Cloud for Customer Price-计价简介
			
SAP Cloud for Customer(本文以下简称C4C)作为SAP新一代的CRM云产品,其Price功能实现虽不如以前的SAP ERP那么复杂,但是也能满足企业运作中各种Price需求. C ...
 - UVA 11988 Broken Keyboard (链表)
			
简单题,题目要求显然是很多次插入,所以是链表. 插入两个语句,nxt[i] = nxt[u] 表示 i结点指向u的后继, nxt[u] = i表示把u的后继设成i. 设置一个头结点,指向一个不存在的结 ...
 - Jquery二维码在线生成(不能生成图片文件)
			
附件地址:http://files.cnblogs.com/files/harxingxing/jQuery%E4%BA%8C%E7%BB%B4%E7%A0%81%E5%9C%A8%E7%BA%BF% ...
 - 《大规模 web服务开发》笔记
			
大规模服务: 可扩展,负载均衡,保证冗余,低运维成本,开发人数和开发方法的变化 数据处理: 磁盘—>内存—>缓存—>CPU 障碍: 持续增长的服务,”无法在内 ...
 - poi实现Excel输出
			
/** * 第一个demo 导出Excel文件 * 第一行 第三个单元格中 写入 zhangsan */ @Test public void test1() throws IOException { ...
 - 协议(Protocol)与委托代理(Delegate)
			
协议(Protocol)的作用: 1. 规范接口,用来定义一套公用的接口: 2. 约束或筛选对象. 代理(Delegate): 它本身是一种设计模式,委托一个对象<遵守协议>去做某件事情, ...
 - VueX源码分析(1)
			
VueX源码分析(1) 文件架构如下 /module /plugins helpers.js index.esm.js index.js store.js util.js util.js 先从最简单的 ...
 - 如何用VS2017用C++语言写Hello world 程序?
			
1,首先,打开VS2017. 2,左上角按文件——新建——项目,或按ctrl+shift+n. 3,按照图片里的选,选完按“确定”. 4,右键“源文件”,再按添加——新建项. 5,剩下的就很简单了,只 ...