软件更新服务之服务端搭建

软件更新服务之服务端搭建

说到软件更新相信大家肯定都不止一次两次见过了吧。在手机上,经常可以看到某某助手或者应用中心提示应用更新,而且会很醒目地告诉你:可以节约多少多少流量。在大家各自的PC上面也不止一次看到这种提示吧。

“检查到新版本x.x.x,当前版本是x.x.x,是否更新”

PC软件提示更新
PC软件提示更新

Android软件提示更新
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
                                                                           # 服务器端运行可以让所有地方访问到

今天文章大概就这样了,代码在手机上面看起来不是很舒服,建议用电脑浏览器打开。后续会给出 软件更新服务之客户端怎么玩的文章以及这个系列的Git仓库,大家可以到GitHub上面fork下来玩玩。所以,想想咱们从头到尾自己实现一个简单的软件更新服务是不是挺有意思的啊,哈哈哈。如果本文存在什么纰漏或者问题,欢迎大家留言回复指正。

猜你喜欢

转载自blog.csdn.net/CBR97/article/details/90183102
今日推荐