zoukankan      html  css  js  c++  java
  • 软件更新服务之客户端更新

    软件更新服务之客户端更新 

    在现在的软件开发和使用中,软件的更新是很关键的一环。通过不停的更新软件,迭代,给用户带来更好的体验和更多的功能以及修复用户反馈的bug。我们在更新的软件的时候,如果每次都要用户从新安装软件的话,想必体验也不会很好,也很麻烦,浪费不必要的资源。
    那么今天就继续给大家说要一下软件更新服务里面的客户度端更新。有些后面关注的同学没看到前面写的那篇服务端搭建的文章的话,可以待会出门左拐看一下。

    豪华分割线


    在这次客户端编写过程当中,为了给大家可以看到更加直观的效果就简单做了个界面,使用到了以下技术:

    PyQt5
    Python3
    python序列化
    urllib下载文件

    大家先在pycharm中,把pyqt5给装上,pip install PyQt5,也可以在设置的里面的project interpreter 里面下载安装。
    接着,就配置好外部工具,QtDesigner以及PyUIC这两个外部工具。
    由于这两个工具的配置比较简单,我就不作说明了,大家可以自行百度一下,随意参考一种都可以顺利配置好这两个外部工具的。
    接着,打开designer来对界面进行绘制设计。

     

     

    大概就这样就可以了,一个标题、一个文本框、两个按钮就足够显示了。
    虽然长得丑了一点,但是我们这次文章的关键不是界面的美化,所以就不作其他处理了。
    保存好,再到pycharm里面对ui文件运行一下PYUIC就OK

     

     

    这个时候,界面代码已经由设计图转成Python代码了,可以看到它生成了一个类,但是还跑不动,因为没有引用到它。所以,我们先放它到一边。

     

     

    接着,我们就重新创建好一个py文件,导入我们预期就要用到的库。

    hashlib 计算MD5用
    sys
    pickle 计算序列化
    urllib 下载文件
    urllib3
    os 处理文件 和目录

    这几个库导进来后,就开始新建一个类,继承刚才生成的那个界面类。写法如下

        python    11行

    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.setupUi(self)
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        mainWindow = MainWindow()
        mainWindow.show()
        sys.exit(app.exec_())
    

    这个时候,运行文件就可以显示出界面了。而且这样将界面和实际操作的代码分隔开来可以避免重新UIC界面时,代码会丢失,而导致要重写的问题。

    OK,界面出来后,就要实现功能了。更新,更新怎么做?
    上一篇更新服务文章已经提供了更新说明和下载服务了,所以,我们这次就利用好这些接口。
    我们又新建一个类,专门用来处理更新文件的,所以就简单的叫UpdateFiles吧。

    在这里再过一次流程:

    从服务器上面拿到清单文件
    反序列清单文件
    比较里面的数据,如果文件存在则计算MD5,相同就跳过,不相同就准备下载
    如果文件不存在,则不用计算MD5了,直接准备下载

    所以,就需要3个函数,下载文件函数、计算MD5值函数、检查更新函数
    按照这三个需求以及上一篇的接口,我们可以很快就完成代码的编写。
    在UpdateFiles这个类中完成这几个功能的开发后,便可以很方便的完成更新文件的服务功能。
    由于已经整理成一个类,所以,后面如果各位希望可以在自己代码中用到这样子的更新服务的话吗,就可以直接将这个类copy过去,改一些东西就可以用了。

    这里说一下写代码踩的坑吧
    1、因为用的是urllib去下载的文件,多级目录下,文件不存在的时候,并不会在目标目录自动新建目录。所以,在下载的时候,需要对路径进行处理,筛选出目标目录,mkdir创建一下目录后,再下载目标文件。具体实现可以看downloadFiles函数,代码很简单,理解起来肯定没问题。

    效果如下

     

     

    点击检查更新会将需要更新的文件列在上面
    点击下载便会自动下载文件了。而且有个简单的进度条可以看到进度。

    代码我就直接贴出来了。

        python    107行

    # -*- coding: utf-8 -*-
    # @Time    : 4/1/2019 19:36
    # @Author  : MARX·CBR
    # @File    : updateClient.py
    import json
    import hashlib
    import sys
    import pickle
    from PyQt5 import QtWidgets
    from urllib3 import request
    from urllib import request
    import os
    
    from updateServer.UClient.sample import Ui_MainWindow
    
    
    class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.setupUi(self)
            self.pushButton.clicked.connect(self.showUpdate)
            self.pushButton_2.clicked.connect(self.updateNow)
            self.updateList = []
            self.updateServer = UpdateFiles()
    
        def showUpdate(self):
            self.textBrowser.clear()
            self.updateList = self.updateServer.check_update()
            for j in self.updateList:
                print(j)
                self.textBrowser.append(j)
    
        def updateNow(self):
            all_file_number = 0
            for j in self.updateList:
                self.updateServer.downloadFiles(j)
                all_file_number += 1
                vau = int((all_file_number * 100) / len(self.updateList))
                self.progressBar.setValue(vau)
                self.repaint()
    
    
    class UpdateFiles():
        def __init__(self):
            self.server = '47.101.195.58'
            self.port = '1213'
            self.directory = os.getcwd()
    
        def downloadFiles(self, key):
            checkurl = 'http://' + self.server + ':' + self.port
            file_dir = self.directory + '\' + key
            file_dir = file_dir.replace('/', '\')
            if os.path.exists(file_dir):
                os.remove(file_dir)
                request.urlretrieve(checkurl + '/' + key, file_dir)
            else:
                newpath = '\'.join(file_dir.split('\')[:-1:])
                print(newpath)
                try:
                    os.mkdir(newpath)
                    request.urlretrieve(checkurl + '/' + key, file_dir)
                except:
                    request.urlretrieve(checkurl + '/' + key, file_dir)
    
        def Getfile_md5(self, 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()
    
        def check_update(self):
            data = {}
            updateList = []
            checkurl = 'http://' + self.server + ':' + self.port
            request.urlretrieve(checkurl + '/.listFile', ".listFile")
    
            with open(".listFile", "rb") as f:
                data = pickle.load(f)
            print(data)
            for key in data:
                new_md5 = data[key]
                file_dir = self.directory + '\' + key
                if os.path.exists(file_dir):
                    oldmd5 = self.Getfile_md5(file_dir)
                    if oldmd5 != new_md5:
                        print(new_md5, "准备下载")
                        updateList.append(key)
                    # print(new_md5)
                else:
                    updateList.append(key)
                    print('准备下载', file_dir)
            return updateList
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        mainWindow = MainWindow()
        mainWindow.show()
        sys.exit(app.exec_())
    

     好了,本次文章就到这里了,这篇是综合上一篇服务端搭建写的。
    打算将这个软件更新服务写几篇内容出来分享给大家的

    这里是第二篇,给大家介绍软件更新服务中,客户端该怎么处理。
    第三篇打算给大家讲一下热更新,如何实现无须重启便完成软件的更新。
    之前那篇服务端搭建的代码存在一些bug,我已经更新了。然后连同本次代码,将整个服务端以及客户端一起提交到GitHub中了。

    欢迎大家到GitHub中fork使用,如果能给个star就 最好啦。

    GitHub地址:https://github.com/97CBR/SoftwareUpdateServer

    推荐阅读:
    软件更新服务之服务端搭建
    是谁让我的线上测试服务器突然变成游戏私服
    安卓简单逆向修改
    搜索引擎的那些小技巧

    本文对你有没帮助呀,喜欢的话,记得留言、点赞、转发呀。谢谢各位!



    扫描关注我的微信公众号哟

     

  • 相关阅读:
    浅谈 iOS 之 Crash log 符号化
    聊聊 Statsd 和 Collectd 那点事!
    如何使用 Zend Expressive 建立 NASA 图片库?
    Nagios 邮箱告警的方式太OUT了!
    如何从软硬件层面提升 Android 动画性能?
    这样查看告警邮件要慢一点……
    Android 共享文件的 Runtime 权限
    第38节:hashCode()与toString()与equals()函数的作用,内部类和匿名内部类
    第37节:多线程安全问题
    第37节:多线程安全问题
  • 原文地址:https://www.cnblogs.com/marxcbr/p/10861564.html
Copyright © 2011-2022 走看看