1.软件打包安装程序
利用setupfactory软件进行客户端软件打包,形成一个setup安装程序。
2. 建立FTP服务器
利用quickeasyftpserver在远程服务器中建立FTP服务器,放置2个文件,一个setup安装文件,一个是ver.txt文件,里面写上软件的版本号12位,例如20200917V001。
3. 客户端程序开发
在客户端程序中点击升级按钮后
(1) 程序首先删除本地的上一次的版本和升级文件,然后从ftp服务器上下载ver.txt,然后判断服务器的setup版本和当前软版本是否一致,不一致,就提示用户升级。
(2) 如果用户同意升级,就在ftp上下载setup安装文件。
(3) 下载完成后,再开一个线程执行setup程序,然后把当前的程序关闭,安装程序会覆盖当前的程序。
问题:
这种方法比较简单,主要问题是不知道ftp文件的下载进度,会有一直卡死的现象。这个原因是进度条的定时器程序刷新UI和FTP下载程序在一个线程中,造成拥塞了。下载时就不能定时中断,刷新UI了
解决方案:
(1) 对于ftp下载采用异步方式,下载完后发送信号给主线程。
(2) 主线程点击升级按钮,绑定子线程和对应的回调函数。然后启动ftp子线程。
(3) 在回调函数中,执行此程序就是下载结束了,这时可以在主线程中启动,进度条满格,然后执行分线程执行安装程序,并在主程序中把自己结束
代码如下:
from update import Ui_MainWindowfrom PyQt5 import QtWidgetsfrom PyQt5.QtWidgets import QMessageBoximport sysimport osfrom ftplib import FTP # 引入ftp模块import win32processfrom PyQt5.QtCore import QBasicTimer, QThread, pyqtSignalimport timemycurrent_ver = '20200916V001' # 当前软件版本号mynew_ver = ''#异步线程class MyCal(QThread): #自定义一个信号名 cal_signal = pyqtSignal(int) #定义信号返回的数值类型 #构造函数 def __init__(self, mypath, filename,parent=None): # super(MyCal, self).__init__(parent) self.mypath = mypath self.filename=filename print("分线程:",self.mypath,self.filename) #析构函数 def __del__(self): self.wait() #该线程主程序 def run(self): ##ftp下载程序版本程序 ftp = MyFtp('127.0.0.1) ftp.login('admin', '123456') ftp.downloadFile(self.mypath, '/down/', self.filename) ftp.close() print("分线程下载结束:", self.mypath+self.filename) self.cal_signal.emit(1) #发射信号,传参数class MyFtp: ftp = FTP() def __init__(self, host, port=21): self.ftp.connect(host, port) def login(self, username, pwd): self.ftp.set_debuglevel(2) # 打开调试级别2,显示详细信息 self.ftp.login(username, pwd) print(self.ftp.welcome) def downloadFile(self, localpath, remotepath, filename): os.chdir(localpath) # 切换工作路径到下载目录 self.ftp.cwd(remotepath) # 要登录的ftp目录 self.ftp.nlst() # 获取目录下的文件 file_handle = open(filename, "wb").write # 以写模式在本地打开文件 self.ftp.retrbinary('RETR %s' % os.path.basename(filename), file_handle, blocksize=1024) # 下载ftp文件 # ftp.delete(filename) # 删除ftp服务器上的文件 def close(self): self.ftp.set_debuglevel(0) # 关闭调试 self.ftp.quit()# 主窗体class MainForm(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self): super(MainForm, self).__init__() self.setupUi(self) self.timer = QBasicTimer() self.step = 0 # self.myupdate_bt() # 进度条控制定时器 def timerEvent(self, event): if self.step >= 100: self.timer.stop() self.pushButton_2.setText('开始进度条') self.step = 0 self.progressBar.setValue(self.step) return self.step = self.step + 1 if self.step>=99: self.step=99 self.progressBar.setValue(self.step) # 进度条控制 def myprocessbar_bt(self): pass if self.timer.isActive(): self.timer.stop() self.pushButton_2.setText('开始进度条') else: self.timer.start(100, self) self.pushButton_2.setText('停止进度条') def myupdate_bt(self): pass myhomedir = os.getcwd() mypath = os.getcwd() + 'down' myfilepath1 = mypath + "ver.txt" myfilepath2 = mypath + "setup.exe" # 删除文件 x1 = os.path.exists(myfilepath1) # True/False if x1 == True: print("删除文件:" + myfilepath1) os.remove(myfilepath1) x1 = os.path.exists(myfilepath2) # True/False if x1 == True: print("删除文件:" + myfilepath2) os.remove(myfilepath2) ##ftp下载程序版本程序 ftp = MyFtp('127.0.0.1) ftp.login('admin', '123456') ftp.downloadFile(mypath, '/down/', 'ver.txt') ftp.close() print("下载结束:", myfilepath1) # 判断版本 with open(myfilepath1, 'rt') as f1: mynew_ver = f1.readline()[0:12] self.label_4.setText(mynew_ver) self.label_2.setText(mycurrent_ver) if mynew_ver != mycurrent_ver: x1 = QMessageBox.information(self, "确认信息", "有新版本,确认是否升级", QMessageBox.Yes | QMessageBox.No) if x1 == QMessageBox.No: os.chdir(myhomedir) return print("开始升级") QMessageBox.information(self, "确认信息", "开始下载程序!!") self.myprocessbar_bt()#显示进度条 # self.timer.start(100, self) ##拥塞ftp下载程序 # ftp = MyFtp('127.0.0.1') # ftp.login('admin', '123456') # ftp.downloadFile(mypath, '/down/', 'setup.exe') # ftp.close() # print("下载结束:", myfilepath2) # QMessageBox.information(self, "确认信息", "下载程序结束!!") ####异步FTP下载 self.cal = MyCal(mypath, 'setup.exe') # 点击按钮后新建计算的线程 self.cal.cal_signal.connect(self.cal_callback) # 连接计算线程的信号 self.cal.start() # 开始运行线程 else: QMessageBox.information(self, "确认信息", "已经是最新版本,不用升级") os.chdir(myhomedir) return # 省略 使用接收到线程返回的参数 ###执行第三方程序,新线程 #win32process.CreateProcess(myfilepath2, '', None, None, 0, win32process.CREATE_NO_WINDOW, None, None,win32process.STARTUPINFO()) os.chdir(myhomedir) print("主程序退出") #sys.exit() def cal_callback(self): # 接收到计算线程信号后的回掉函数 pass print('异步ftp下载结束') self.step=100 self.progressBar.setValue(self.step) #self.myprocessbar_bt()#显示进度条 myhomedir = os.getcwd() mypath = myhomedir myfilepath1 = mypath + "ver.txt" myfilepath2 = mypath + "setup.exe" QMessageBox.information(self, "确认信息", "下载结束,开始升级") print(myfilepath2) win32process.CreateProcess(myfilepath2, '', None, None, 0, win32process.CREATE_NO_WINDOW, None, None,win32process.STARTUPINFO()) sys.exit()# 主程序入口if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) win_main = MainForm() win_main.show() sys.exit(app.exec_())
界面如下