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之路 - 网络编程之粘包 粘包
随机推荐
- ubuntu14.04按照mysql5.7
1.安装mysql5.5 https://www.cnblogs.com/zhuyp1015/p/3561470.html https://www.cnblogs.com/ruofengzhishan ...
- MT【325】垂心的向量形式
设$H$为垂心,且$3\overrightarrow{HA}+4\overrightarrow {HB}+5\overrightarrow {HC}=\overrightarrow 0$,则$\cos ...
- Codeforces 1092F Tree with Maximum Cost(树形DP)
题目链接:Tree with Maximum Cost 题意:给定一棵树,树上每个顶点都有属性值ai,树的边权为1,求$\sum\limits_{i = 1}^{n} dist(i, v) \cdot ...
- Custom DNS on Ubuntu 18.04LTS server
1. Edit resolved config file nano /etc/systemd/resolved.conf 2. Replace #DNS into DNS DNS=9.9.9.9 1. ...
- MATLAB-卡尔曼滤波简单运用示例
1.角度和弧度之间的转换公式? 设角度为 angle,弧度为 radian radian = angle * pi / 180; angle = radian * 180 / pi; 所以在matla ...
- Unity 案例
Unity 案例-用Unity 开发的产品 水电站管理.监控.培训系统 石油加工管理系统 房地产开发 污水处理系统 陆海空军事训练 城市和社区监控,管理系统 虚拟展馆 家庭自动化系统 石油加工管理系统 ...
- cannot update the cursor rep,since it is read-only
操作DBF文件,开发机器读写都OK,但部署到服务器上后报:cannot update the cursor rep,since it is read-only 网上寻找解决方案英文答案比较多,也没有给 ...
- Dynamics CRM 如何修复 Access Is Denied - ObjectTypeCode: 2500 的错误
最近被 Dynamics CRM 的权限配置问题恶心了一个星期,老是报“Access Is Denied”,几经波折,最后终于找到一个比较合适的解决方案,写个博客 mark 下来,方便以后查看. 首先 ...
- EF Code First一对一、一对多、多对多关联关系配置
1.EF Code First一对一关联关系 项目结构图: 实体类: Account.cs using System; using System.Collections.Generic; using ...
- iview-admin安装
桌面创建project文件夹. 文件夹内右键选择gitbash here,输入git init.文件夹内会生成.git文件夹. 再输入git config --global user.name &qu ...