軟件更新服務之服務端搭建
說到軟件更新相信大家肯定都不止一次兩次見過了吧。在手機上,經常可以看到某某助手或者應用中心提示應用更新,而且會很醒目地告訴你:可以節約多少多少流量。在大家各自的PC上面也不止一次看到這種提示吧。
“檢查到新版本x.x.x,當前版本是x.x.x奇跡服務端修改教程,是否更新”
PC軟件提示更新
軟件提示更新
這種軟件更新是怎么做到的呢?拋開的不說奇跡服務端修改教程,咱們本次討論一下PC的軟件是如何做到的怎么樣?
其實,流程是十分簡單的,大家也是一想就能明白。
流程如下:
首先,咱們得先有一部遠程服務器吧。用來存放軟件更新的文件以及清單文件,以及搭建一個服務用以軟件檢測是否存在有新版本和下載新文件用
接著軟件客戶端,就是你的PC上面要有個服務去檢測發現版本更新信息。可以在啟動的時候,也可以在你點擊軟件檢查更新的時候去檢查版本信息。
點擊更新后,下載清單文件,然后再比較一下清單文件和本地文件的差異,可以檢測一下文件的MD5什么的。如果不一樣的就下載更新,當然如果是不存在的,就更加得下載下來啦。
最后就是……你得有網,,曉得吧,木得談自動更新(增量更新)都是“耍流氓”。。。
流程圖如下:
最最最簡單的流程
OK ,那么這個這么簡單的流程咱們搞清楚了嗎?
清楚后,咱們分析一下我們服務器擔任的角色。我們今天先不管客戶端啦(雖然考慮的時候應該一起考慮,小聲bb)
服務器要起到幾個作用:
1、提供網絡服務,就是得有簡單文件下載服務和應答服務。
2、得有個文件夾存放更新文件,里面放更新文件和清單文件。
3、在網絡中任意一個位置都可以訪問到,而不僅限于自己的那個路由器……
所以,我們瞬間就可以想起了中自帶的那個網絡服務。。。但是,用過的人都知道它實在是太簡單,難以勝任我們的這個需求啊。所以,這個時候,我們可以選用Flask這個小辣椒啦。什么?你不知道Flask是什么?
就是這個火藥筒
簡單普及一波:其實Flask那個圖片不是辣椒啦,人家是裝火藥的啦
基于他,我們可以很容易地快速搭建好我們自己定義的服務。
再扯一下,單純用這個框架簡單地寫個服務還是可以能應付一般點的并發量的。。。太大的并發量的話,就得采用其他策略去對付了。所以,我們現在討論的是不考慮高并發情況的。
代碼我直接就放上來吧。注釋都有寫作用的。
下面我就簡單解釋一下各函數的寫法思路吧。
5行
download,接收filename的參數,表示下載的文件名。獲取后,通過flak的內置方法返回所需下載文件即可
Getfile_md5,接收文件路徑作為參數,通過文件路徑讀取文件,然后通過hashlib計算MD5然后返回
generate,沒有參數,用于更新清單文件。(雖然感覺這個做法有點多余,因為可以多寫一個獨立的文件處理,管理員上傳完文件后再執行一次就OK了D)
findFile,接收目錄路徑作為參數,遞歸查找目標目錄里面的文件,如果是文件則計算MD5是目錄則遞歸進去尋找文件。
check,沒有參數,返回當前服務器版本號以及更新信息。
函數的目的就是這么簡單。簡簡單單幾十行就可以把這個服務給實現出來了。后面PC客戶端在請求是否有新版本更新的時候,就可以用這個服務腳本來處理了。
當然,這里面還是有挺多沒考慮到的問題的。比如被人家惡意下載導致服務器流量快速被消耗,高并發的狀態下,它是否能頂的住?
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("/", 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倉庫,大家可以到上面fork下來玩玩。所以,想想咱們從頭到尾自己實現一個簡單的軟件更新服務是不是挺有意思的啊,哈哈哈。如果本文存在什么紕漏或者問題,歡迎大家留言回復指正。