一种简单的客户端更新方案

在c/s结构的程序中,客户端自动更新是简化部署的一个常见需求.更新实际上做的操作是:

  • 与服务器当前的文件做diff,找出所有变动的文件
  • 下载变动的文件,替换掉本地的文件

从这两个操作来看,服务器起码要向客户端提供两个功能:

  • 当前有那些文件
  • 下载文件

其实第一个功能也可以转为下载文件,只要提供描述当前文件列表信息的文件就行了。通常有两种更新模式,增量更新与直接更新。增量更新是指低版本向高版本逐版本更新,这种方式的好处在于,服务器发布新版本时可以直接预生成diff补丁包,客户端直接按照补丁包进行替换,但坏处是:

  • 跨版本比较多时,会进行重复操作
  • 管理起来麻烦,要保存所有历史版本

直接升级则不会有重复操作,且服务器只要保存一个最新版本即可.本文描述的方案就是直接升级的.

服务端

基于文件服务器工作,FTP或者HTTP.用两个json文件来管理版本,app.json和appflist.json.文件服务器上的结构为:

  • 文件服务器根目录
  • app1
  • app2

app就表示客户端的根目录,每个app里都会有app.json和appflist.json.服务器的开发工作就是生成这两个文件,以及更新app目录.

app.json

{"version":"1.0.0","info":"版本信息"}

用于描述版本号与版本信息,主要给客户端进行快速判断是否要升级.客户端可以简单的判断版本号是否相等来决定要不要升级.

appflist.json

[{"path":"foo.dll","md5":"","ctime":147989119}]

用于描述文件列表信息,包含当前版本所有文件信息(除app.json,appflist.json),用于给客户端做diff.

path 为客户端根目录的相对路径

客户端

客户端通过本地的app.json和appflist.json与服务器上的同名文件来决定更新操作。更新时会用ftp://127.0.0.1/app1/foo.dll这样的url去下载文件,url的格式为协议://host:port/app目录/文件路径

更新分为五个步骤:

  1. 判断是否要更新 通过比对app.json的version来决定是否要更新
  2. diff 下载appflist.json,然后通过md5筛选出增删改的文件
  3. 下载变动的文件 用path和app名下载增改的文件
  4. 本地替换 进行增删改操作
  5. 删除下载的文件

在更新时要注意用独立的进程操作,因为要替换主程序的文件.

还有如何处理更新失败的情况,更新失败有两种情况:

  • 更新时程序被强制结束
  • 文件操作时失败

第一种情况发生时,如果正在替换文件,可能会损坏文件,导致主程序不能正常打开,这个问题不在于文件损坏,而是主程序无法运行,也就不能再次进入更新流程了,如果能进来则把流程重来一次就好了,不能进来时只能让用户手动打开更新程序了.因此这种情况是不需要在客户端写特定代码处理的.
第二种情况发生时,也直接重试流程,如果一直错,那可能是无操作文件的权限,此时并不会损坏旧文件,因此也不需要特殊处理.


最后我写了一个shupd实现了这些功能,放在github上,shupd的server部分为一个用来生成app.json,appflist.json,拷贝变动文件的工具;client部分为c实现的动态库。目前基于ftp工作,有兴趣的朋友可以看看.

原文地址:https://www.cnblogs.com/watercoldyi/p/6683695.html