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 ...
随机推荐
- Android tess_two Android图片文字识别
文字识别一般都用的tesseract-ocr. GitHub:https://github.com/tesseract-ocr/tesseract 而Android对应的比较推荐的有个tess-two ...
- Setting 之dashboard 点击跳转流程
设置的主界面的可以通过修改xml中的dashboard_categaries.xml 文件实现,在DashboardSummary.java 文件中的rebuildUI()方法中将xml对应的实体类转 ...
- Python +selenium之设置元素等待
注:本文转载http://www.cnblogs.com/mengyu/p/6972968.html 当浏览器在加载页面时,页面上的元素可能并不是同时被加载完成,这给元素的定位增加了困难.如果因为在加 ...
- java面试题(杨晓峰)---第四讲强引用、软引用、弱引用、幻想引用有什么区别?
在java语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握java对象生命周期和JVM内部相关机制非常有帮助. 今天问题:强引用.软引用.弱引用.幻想引 ...
- BZOJ 4175: 小G的电话本 SAM+FFT
4175: 小G的电话本 Time Limit: 45 Sec Memory Limit: 256 MBSubmit: 195 Solved: 48[Submit][Status][Discuss ...
- ABAP的Package interface, 安卓的manifest.xml和Kubernetes的Capabilities
ABAP 事务码SE21创建ABAP包接口.这是ABAP基于包层面的访问控制实现逻辑.包里可以存储很多ABAP对象.如果开发人员想将某些对象声明为包外程序也能访问,可以将这些对象放在包接口的Visib ...
- OpenLayers 3 的 图层控制控件
openlayers3的control中没有提供默认的图层控制控件. 但是git上已经有造好的轮子,直接拿来用就可以了.地址 https://github.com/walkermatt/ol3-lay ...
- Predicate Programming Guide
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/AdditionalChap ...
- 动态代理--Cglib
JDK 的Proxy 实现,需要代理对象实现接口: package com.utils; import java.lang.reflect.InvocationHandler; import java ...
- Bootstrap历练实例:默认的面板(Panels)
Bootstrap 面板(Panels) 本章将讲解 Bootstrap 面板(Panels).面板组件用于把 DOM 组件插入到一个盒子中.创建一个基本的面板,只需要向 <div> 元素 ...