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之路 - 网络编程之粘包 粘包
随机推荐
- DRF 商城项目 - 购物( 购物车, 订单, 支付 )逻辑梳理
购物车 购物车模型 购物车中的数据不应该重复. 即对相同商品的增加应该是对购买数量的处理而不是增加一条记录 因此对此进行联合唯一索引, 但是也因此存在一些问题 class ShoppingCart(m ...
- [PRIMITIVE TECHNOLOGY]澳洲小哥的黑皮豆/black been/摩顿湾板栗(栗子)/Moreton Bay Chestnut
wiki:https://en.wikipedia.org/wiki/Castanospermum inner:http://blog.sciencenet.cn/blog-309517-770951 ...
- [PKUWC2019]Day1 T2 你和虚树的故事
选择k个颜色,使得颜色的虚树有交的方案数 肯定要考虑连通块的贡献. 法一 https://www.cnblogs.com/xzz_233/p/10292983.html 枚举连通块还是不可行的. 枚举 ...
- win 10 dpi:150% 与 win 7 dpi:150% 的不同之处
由于 win 7 和 win 10 的 dpi 处理方式不同,导致我们写的客户端程序在 win 7 上运行正常,在 win 10(dpi:150%)上运行不正常了. 具体的描述,可参考:解决win10 ...
- Mac下查看已安装的jdk版本及其安装目录
1.打开终端,输入:/usr/libexec/java_home -V 注意:输入命令参数区分大小写(-v是不对的,必须是-V) 2.如图:为输入命令: 当前Mac已安装jdk目录: Mac默认使用的 ...
- linux 常用命令集锦
喝断片儿了,我是谁?我在什么地方?我做过些什么事?查看当前用户 who am i查看当前路径 pwd查看历史记录 history 我忘了程序放哪了,就记得个名.更新系统数据库 updatedb查找文件 ...
- mysql8.0.15二进制安装
mysql8.0.15二进制安装 今天有幸尝试安装了社区版本的mysql8.0.15,记录下来,供以后方便使用.特此感谢知数堂的叶老师,提供了配置文件的模板. # 第一部分:系统配置 # 1.安装系统 ...
- Java IO系列之二:NIO基本操作
核心部分 NIO( New Input/ Output) , 引入了一种基于通道和缓冲区的 I/O 方式,NIO 是一种同步非阻塞的 IO 模型.同步是指线程不断轮询 IO 事件是否就绪,非阻塞是指 ...
- metasploit与Cobaltstrike互相派生shell
msf 派生 shell 给 Cobalt strike(前提有一个meterpreter) msf exploit(handler) > use exploit/windows/local/p ...
- 自搭的一个系统框架,使用Spring boot+Vue+Element
基于:jdk1.8.spring boot2.1.3.vue-cli3.4.1 特性: ~ 数据库访问使用spring data jpa+alibaba druid ~ 前后端数据交互使用 ...