Python网络编程之黏包问题
二、解决黏包问题
2.1 解决黏包方法1
- 计算消息实体的大小
- 服务端接受两次,一次时消息大小,二次是消息实体,解决消息实体黏包
- 客户端发送两次,一次是消息大小,一次是消息实体
- 在两次收发之间加入一次多余通信,以防止消息大小和消息实体黏包
server端
import socket sk = socket.socket() sk.bind(('127.0.0.1',9000))
sk.listen() conn,addr = sk.accept()
print(conn,addr)
while True:
cmd = input('请输入你的命令: ')
if cmd == 'q':
break conn.send(cmd.encode('gbk'))
data_length = conn.recv(1024).decode('gbk')
conn.send(b'ok') # 接受到消息大小后马上send,这样可以隔开两次recv,并且第二次接受指定长度的消息
data = conn.recv(int(data_length)).decode('gbk')
print(data) conn.close()
sk.close()
client
import socket
import subprocess
sk = socket.socket() sk.connect(('127.0.0.1',9000)) while True:
cmd = sk.recv(1024).decode('gbk')
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
std_out = ret.stdout.read()
std_err = ret.stderr.read() data_length = str(len(std_out)+len(std_err)).encode('gbk')
sk.send(data_length)
sk.recv(1024) # send消息大小后马上转入recv,隔开两次send。
sk.send(std_out)
sk.send(std_err) sk.close()
2.2 借助于struct模块
server端
import socket
import struct sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen() conn,addr = sk.accept() while True:
cmd = input('请输入命令: ')
conn.send(cmd.encode('utf-8'))
data_length_struct = conn.recv(4)
data_length = struct.unpack('i',data_length_struct)[0]
res = conn.recv(data_length).decode('gbk')
print(res) conn.close()
sk.close()
client端
import socket
import subprocess
import struct sk = socket.socket()
sk.connect(('127.0.0.1',8080)) while True:
cmd = sk.recv(1024).decode('utf-8')
res = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout = res.stdout.read()
std_err = res.stderr.read()
data_length = len(stdout) + len(std_err)
data_length_struct = struct.pack('i',data_length)
sk.send(data_length_struct)
sk.send(stdout)
sk.send(std_err) sk.close()
2.3 通过struct定制报头传输大文件
server端
import socket
import struct
import json sk = socket.socket()
sk.bind(('127.0.0.1',8090))
sk.listen()
buffer = 2048 conn,addr = sk.accept() # 先接受报头
# 根据报头接受消息实体 struct_length = conn.recv(4) # 接受struct长度的包
bytes_head_length = struct.unpack('i',struct_length)[0] # 计算报头的长度
bytes_head = conn.recv(bytes_head_length) # 接受报头
json_head = bytes_head.decode('utf-8') # 将报头转换为str
head = json.loads(json_head) # 将报头转换为字典
fileSize = head['fileSize'] with open(head['fileName'],'wb') as f:
while fileSize:
if fileSize >= buffer:
content = conn.recv(buffer)
f.write(content)
fileSize -= buffer
else:
content = conn.recv(fileSize)
f.write(content)
break conn.close()
sk.close()
client端
import socket
import os
import json
import struct sk = socket.socket()
sk.connect(('127.0.0.1',8090))
buffer = 2048
# 定制报头
# 先发送报头大小
# 发送报头
# 发送消息实体
head = {'fileSize':None,
'fileName':r'a.tar.gz',
'filePath':r'C:\Users\王诚\Desktop'}
file = os.path.join(head['filePath'],head['fileName'])
fileSize = os.path.getsize(file)
head['fileSize'] = fileSize
json_head = json.dumps(head) # 字典转换成了字符串
bytes_head = json_head.encode('utf-8') # 将字符串的head转换为bytes类型
bytes_head_length = len(bytes_head) # 计算bytes类型的head的大小 struct_length = struct.pack('i',bytes_head_length) # 通过struct转换为固定长度的bytes
sk.send(struct_length) # 先发报头的长度
sk.send(bytes_head) # 发报头
with open(file,'rb') as f:
while fileSize:
if fileSize >= buffer:
content= f.read(buffer)
sk.send(content)
fileSize -= buffer
else:
content = f.read(fileSize)
sk.send(content)
break sk.close()
三、检查客户端的合法性
使用hmac
server端
import socket
import os
import hmac secret_key = b'wangys' sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen() def check_conn(conn):
msg = os.urandom(32)
conn.send(msg)
h = hmac.new(secret_key,msg)
server_msg = h.digest()
client_msg = conn.recv(1024)
res = hmac.compare_digest(server_msg,client_msg)
return res conn,addr = sk.accept()
res = check_conn(conn)
if res:
print('合法的客户端')
conn.close()
else:
print('不合法的客户端')
conn.close() sk.close()
client端
import socket
import hmac
secret_key = b'wangys' sk = socket.socket()
sk.connect(('127.0.0.1',8080)) msg = sk.recv(1024)
h = hmac.new(secret_key,msg)
client_msg = h.digest()
sk.send(client_msg) sk.close()
Python网络编程之黏包问题的更多相关文章
- Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性
TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...
- 《Python》网络编程之黏包
黏包 一.黏包现象 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包. server端 import socket sk = s ...
- python socket编程和黏包问题
一.基于TCP的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端,有顺序,不重复,可靠.不会被加上数据边界. server端 import socket sk = so ...
- 网络编程- 解决黏包现象方案二之struct模块(七)
上面利用struct模块与方案一比较,减少一次发送和接收请求,因为方案一无法知道client端发送内容的长度到底有多长需要和接收OK.多一次请求防止黏包,减少网络延迟
- Python网络编程,粘包、分包问题的解决
tcp编程中的粘包.分包问题的解决: 参考:https://blog.csdn.net/yannanxiu/article/details/52096465 服务端: #!/bin/env pytho ...
- python网络编程-socket“粘包”(小数据发送问题)
一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ...
- python网络编程之粘包
一.什么是粘包 须知:只有TCP有粘包现象,UDP永远不会粘包 粘包不一定会发生 如果发生了:1.可能是在客户端已经粘了 2.客户端没有粘,可能是在服务端粘了 首先需要掌握一个socket收发消息的原 ...
- Python网络编程与并发编程
网络编程基础 黏包 , 并发 计算机网络的发展及基础网络概念 Python 中的进程与 锁 Python IO 多路复用 \协程
- Python之路 - 网络编程之粘包
Python之路 - 网络编程之粘包 粘包
随机推荐
- 【集训队作业2018】矩阵玩小凹 NTT
题目大意 有一个 \(n\times m\) 的矩阵 \(A\),每个元素都是 \([0,1]\) 内的等概率随机实数,记 \(s_i=\sum_{j=1}^mA_{i,j}\),求 \(\lfloo ...
- Java代码的编译与反编译那些事儿
原文:Java代码的编译与反编译那些事儿 编程语言 在介绍编译和反编译之前,我们先来简单介绍下编程语言(Programming Language).编程语言(Programming Language) ...
- 【BZOJ4029】[HEOI2015]定价(贪心)
[BZOJ4029][HEOI2015]定价(贪心) 题面 BZOJ 洛谷 题解 每次加上十进制下的\(lowbit\)就行了??? #include<iostream> #include ...
- pwn-格式化字符串漏洞
原理:因为没有正确使用printf()函数 正确使用 : printf('%s',str) 不正规使用:printf(str) 控制字符串str可以爆出stack内内容从而实现任意地址读或者任意地址写 ...
- python第十三天,函数的嵌套定义,global,nonlocal关键字的使用,闭包及闭包的运算场景,装饰器
今日内容 1. 函数的嵌套定义 2.global,nonlocal关键字 3.闭包及闭包的运用场景 4.装饰器 函数的嵌套定义 1. 概念:在一个函数内部定义另一个函数 2 .为什么要有函数的嵌套定义 ...
- Security+ 认证考过经验分享 802分飘过
PART 1/考前准备 1.针对与新人.学生建议看每一节直播课程,老师会结合自己的工作工作经验讲解课程,可以帮助学生理解知识. 2.备考期间建议官方指导手册至少看两遍以上,我在结合自己的做题库时发现有 ...
- python模拟蒙特·卡罗法计算圆周率
蒙特·卡罗方法是一种通过概率来得到问题近似解的方法,在很多领域都有重要的应用,其中就包括圆周率近似值的计问题. 假设有一块边长为2的正方形木板,上面画一个单位圆,然后随意往木板上扔飞镖,落点坐标(x, ...
- finalize()与PhantomReference学习笔记
众所周知,Java语言提供了自动垃圾回收机制,使得程序员不用考虑自己释放不再使用的内存.既然回收内存的活都让Java自己干了,程序员在这方面能干的事情就不多了.尽管如此,Java也提供了一些让程序员对 ...
- python--再看并行之协程线程进程
1.gevent协程适合I/O密集,不适合CPU密集. 3.gevent协程无法发挥多核优势,事实上,协程只是以单线程的方式在运行. 3.子程序就是协程的一种特例 项目实际应用 from gevent ...
- Ext.net按钮事件中使用Response.Redirect的一个问题
今天遇到一个Response.Redirect问题 通过Ext.net按钮写发送事件时,连接中会多出一个&,如果后台不进行UrlEncode操作的话,就会出问题,可是很不幸的是,有些跳转 ...