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 ...
随机推荐
- 本号讯 | 永不消失的协作“空间站”开课;微软推出微软云Azure文档网站
8月29日,针对企业常面临的“协同办公”困难,开展以“还有这种操作?永不消失的协作'空间站'”为主题的协同办公培训课. 课程内容包含:在Office 365环境中,如何利用Teams与Groups等功 ...
- Selenium3+webdriver学习笔记4(css方式元素定位)
#!/usr/bin/env python# -*- coding:utf-8 -*- from selenium import webdriver import time,os # about:ad ...
- UOJ #205/BZOJ 4585 【APIO2016】Fireworks 可并堆+凸包优化Dp
4585: [Apio2016]烟火表演 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 115 Solved: 79[Submit][Status] ...
- EF生成的实体映射含义
如图: 组合效果: LEFT JOIN 效果: this.HasOptional(t => t.子表) .WithMany(t => t.主表) .HasForeignKey(d => ...
- UVA 11925 Generating Permutations 生成排列 (序列)
题意:要用一个有序的序列生成给定序列,操作有两种,一是交换前两个元素,二是把第一个元素移动到最后去. 思路有两种: 1.映射,把给定序列映射成有序的序列,然后按照同样的替换规则把有序的序列映射掉,然后 ...
- [论文理解] CornerNet: Detecting Objects as Paired Keypoints
[论文理解] CornerNet: Detecting Objects as Paired Keypoints 简介 首先这是一篇anchor free的文章,看了之后觉得方法挺好的,预测左上角和右下 ...
- [视觉] 基于YoloV3的实时摄像头记牌器
基于YoloV3的实时摄像头记牌器 github:https://github.com/aoru45/cards_recognition_recorder_pytorch 最终效果 数据准备 数据获取 ...
- Python-OpenCV——Image inverting
通常我们将读入的彩色图转化成灰度图,需要将灰度图反转得到掩码,如何正确快速的得到某个图像的反转图呢? 首先看一种看似很正确的写法,对其中每个像素进行如下处理: img[x,y] = abs(img[x ...
- groupmod - 修 改 群 组
总览 SYNOPSIS groupmod [-g gid [-o]] [-n group_name ] group 描述 DESCRIPTION groupmod 命 令 会 参 照 你 命 令 列 ...
- Luogu P2073 送花
权值线段树的模板题 然而AC后才发现,可以用\(\tt{set}\)水过-- 权值线段树类似于用线段树来实现平衡树的一些操作,代码实现还是比较方便的 #include<iostream> ...