软件更新服务之服务端搭建
说到软件更新相信大家肯定都不止一次两次见过了吧。在手机上,经常可以看到某某助手或者应用中心提示应用更新,而且会很醒目地告诉你:可以节约多少多少流量。在大家各自的PC上面也不止一次看到这种提示吧。
“检查到新版本x.x.x,当前版本是x.x.x,是否更新”
PC软件提示更新
Android软件提示更新
这种软件更新是怎么做到的呢?抛开Android的不说,咱们本次讨论一下PC的软件是如何做到的怎么样?
其实,流程是十分简单的,大家也是一想就能明白。
流程如下:
首先,咱们得先有一部远程服务器吧。用来存放软件更新的文件以及清单文件,以及搭建一个服务用以软件检测是否存在有新版本和下载新文件用
接着软件客户端,就是你的PC上面要有个服务去检测发现版本更新信息。可以在启动的时候,也可以在你点击软件检查更新的时候去检查版本信息。
点击更新后,下载清单文件,然后再比较一下清单文件和本地文件的差异,可以检测一下文件的MD5什么的。如果不一样的就下载更新,当然如果是不存在的,就更加得下载下来啦。
最后就是……你得有网,Internet,晓得吧,木得Internet谈自动更新(增量更新)都是“耍流氓”。。。
流程图如下:
最最最简单的流程
OK ,那么这个这么简单的流程咱们搞清楚了吗?
清楚后,咱们分析一下我们服务器担任的角色。我们今天先不管客户端啦(虽然考虑的时候应该一起考虑,小声bb)
服务器要起到几个作用:
1、提供网络服务,就是得有简单文件下载服务和应答服务。
2、得有个文件夹存放更新文件,里面放更新文件和清单文件。
3、在网络中任意一个位置都可以访问到,而不仅限于自己的那个路由器……
所以,我们瞬间就可以想起了Python中自带的那个网络服务。。。但是,用过的人都知道它实在是太简单,难以胜任我们的这个需求啊。所以,这个时候,我们可以选用Flask这个小辣椒啦。什么?你不知道Flask是什么?
就是这个火药筒
简单普及一波:其实Flask那个图片不是辣椒啦,人家是装火药的啦
基于他,我们可以很容易地快速搭建好我们自己定义的服务。
再扯一下,单纯用这个框架简单地写个服务还是可以能应付一般点的并发量的。。。太大的并发量的话,就得采用其他策略去对付了。所以,我们现在讨论的是不考虑高并发情况的。
代码我直接就放上来吧。注释都有写作用的。
下面我就简单解释一下各函数的写法思路吧。
5行
download,接收filename的参数,表示下载的文件名。获取后,通过flak的内置方法返回所需下载文件即可
Getfile_md5,接收文件路径作为参数,通过文件路径读取文件,然后通过hashlib计算MD5然后返回
generate,没有参数,用于更新清单文件。(虽然感觉这个做法有点多余,因为可以多写一个独立的文件处理,管理员上传完文件后再执行一次就OK了D)
findFile,接收目录路径作为参数,递归查找目标目录里面的文件,如果是文件则计算MD5是目录则递归进去寻找文件。
check,没有参数,返回当前服务器版本号以及更新信息。
函数的目的就是这么简单。简简单单几十行就可以把这个服务给实现出来了。后面PC客户端在请求是否有新版本更新的时候,就可以用这个服务脚本来处理了。
当然,这里面还是有挺多没考虑到的问题的。比如被人家恶意下载导致服务器流量快速被消耗,高并发的状态下,它是否能顶的住?
python 95行
# -*- coding: utf-8 -*-
# @Time : 4/1/2019 19:27
# @Author : MARX·CBR
# @File : __init__.py.py
import pickle
from flask import request, jsonify, send_from_directory, abort, Flask
import os
import hashlib
import json
app = Flask(__name__)
allfile = []
md5_list = []
updateList = {}
directory = os.getcwd()
# 下载文件服务
@app.route("/<filename>", methods=['GET'])
def download(filename):
if request.method == "GET":
if os.path.isfile(os.path.join('updateFiles', filename)):
return send_from_directory('updateFiles', filename, as_attachment=True)
abort(404)
# 计算文件MD5
def Getfile_md5(filename):
if not os.path.isfile(filename):
return
myHash = hashlib.md5()
f = open(filename, 'rb')
while True:
b = f.read(8096)
if not b:
break
myHash.update(b)
f.close()
return myHash.hexdigest()
# 计算生成新的清单文件
@app.route("/generateNewConfig", methods=['GET'])
def generate():
findFile(directory + '/updateFiles/')
file_md5_list = json.dumps(updateList)
print(file_md5_list)
with open('./updateFiles/listFile', 'wb') as f:
pickle.dump(updateList, f)
return_data = {
'Statu': 'success',
}
return jsonify(return_data)
# file_md5_list=json.load(updateList)
# 找到更新文件目录里面的文件以及文件夹、递归寻找
def findFile(path):
fsinfo = os.listdir(path)
for fn in fsinfo:
temp_path = os.path.join(path, fn)
if not os.path.isdir(temp_path):
print('文件路径: {}'.format(temp_path))
fm = Getfile_md5(temp_path)
print(fn)
fn = temp_path.replace(directory + "/updateFiles/", '')
updateList[fn] = fm
else:
findFile(temp_path)
# 检查更新版本,该部分尚未够,完善。可以考虑为管理员远程上传文件的时候
# 将更新说明以json格式一同上传到服务器中,更新时直接读取即可
@app.route("/checkUpdate", methods=['GET'])
def check():
if request.method == "GET":
return_data = {
'Version': '0.0.1',
'Msg': '更新文件,修复初始化卡顿bug\n增加文件预下载功能',
}
return jsonify(return_data)
# 首页Hello
@app.route("/", methods=['GET'])
def hello():
if request.method == "GET":
return "Hello MARXCBR"
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080) # 运行,指定监听地址为 0.0.0.0:8080
# 服务器端运行可以让所有地方访问到
今天文章大概就这样了,后续会给出 软件更新服务之客户端怎么玩的文章。咱们从头到尾自己实现一个简单的软件更新服务,哈哈哈。如果本文存在什么纰漏或者问题,欢迎大家留言回复。