关于客户端Launcher的设计和实现的一些思路
本文由@苍月未离 出品,转载请注明出处。
文章链接: http://blog.csdn.net/u014511876/article/details/78901370
近期因为公司的产品需要一个Launcher来实现更新版本,写了一段时间算是完工了,但是其中也发现了不少的问题,在此把实现思路和一些在开发过程中遇到的一些问题写出来,有需要的朋友可以用于参考。
PS:由于是公司的项目,此篇文章主要讲一个实现的思路和开发过程中遇到的问题,不会涉及到源代码。
大致流程
先大致的介绍一下更新的流程和实现思路,在后面会详细的进行讨论。
要实现更新客户端,首先需要一个下载最新客户端的地方,也就是首先需要把最新的客户端文件放在服务器上或者云储存上,并对外提供下载链接。
有了下载链接后,那么下一步就是确定哪些文件需要被更新,检索出新增文件,被改动的文件,被移除的文件,然后确定需要更新的文件列表。
确定了哪些文件需要更新后,就是下载的过程了,把需要更新文件下载覆盖原来的文件。
以上是更新的大致流程,虽然看起来流程十分简单,但是要实现起来还是有十分多的细节要注意。
提供客户端下载链接
关于最新客户端放在服务器或者云储存上的问题,如果公司本身有服务器的,可以放在公司服务器上,也可以选择现在市面上比较成熟的云储存提供商,如阿里云,腾讯云,七牛云等,在此不过多赘述。
检测版本
接下来为了检测是否需要被更新,需要获取最新的客户端版本号,和当前的版本号进行对比,若发现版本号不一致即为需要更新。
关于如何获取最新版本号的方法,不了解Socket通信的朋友,如果公司没有后端开发,这一步对你来可能就有些困难了,你或许需要从服务端的搭建开始了解,如果有后端的话,可以让后端提供获取数据的接口,通过相应的协议和URL调用API即可,虽然也需要了解一定的网络通信,但是无疑比从服务端开始搭建容易太多了,况且几乎每种语言都有相应的Socket库,只需要了解库的用法即可,本篇主要讲Launcher的实现,所以在此不专门讨论。
关于获取当前客户端的版本号,方法有很多,比如说创建一个专门用于储存版本号的version.ini文件,也可以修改客户端执行程序的版本号属性,具体采用哪种方法,可以根据你的喜好而定。
检测客户端进程
更新前,需要对客户端进程进行检测,因为客户端如果在启动中,会造成文件被占用无法更新的情况,所以需要先检测当前进程中是否存在客户端进程,提示用户关闭客户端后再进行更新。
检索需更新文件
确认了版本差异后,就需要检索出哪些文件需要更新,比较普遍的方法是每个版本都制作一份文件对照表,
文件对照表中记录着每个文件的相对路径和文件名,以及文件特征码等信息,文件特征码可以采用目前使用比较广泛MD5。
所以在此之前,需要先开发一个文件对照表的程序,遍历客户端的所有文件,生成对应相对文件名和文件特征码的表格,再把文件对照表数据上传到数据库中,每一个版本都需要生成一份对应的文件对照表。
由后端提供接口,通过查询版本号的方式获取当前和最新的文件对照表,进行相对路径和文件名以及特征码差异对比,检索出新增文件,被改动的文件,被移除的文件,其中新增文件和被改动文件就是需要更新下载的部分,被移除的文件直接删除即可。
PS:其中这里有些朋友可能会有些疑问,觉得获取当前文件对照表是否太过于麻烦了,直接获取当前客户端的路径,对文件进行遍历检索不行吗?虽然说这种方法的确是可行的,但是却有着很大的风险,如果用户把客户端目录放在了某个驱动器的根目录,那么如果使用这种方法,就会自动把整个驱动器的文件当做客户端文件进行检索,其结果就会是直接删除掉整个驱动器的其余文件,只留下客户端文件,不得不说这是相当可怕的事情。
下载需更新文件
首先下载的话需要获取到下载文件的URL,在文件对照表中,可以记录下载用服务器域名,整体文件的下载URL则为下载用服务器域名+文件相对路径及文件名。
下载文件的方法有很多,也有不少成熟且开源的文件下载库,下面简单介绍一下我的下载方式。
下载器主体采用HTTP协议请求传输文件,由于项目的客户端文件体积比较大,所以提高下载速度和实现断点续传是必要的,若想支持断点续传,首先需要服务器支持Range请求头,如果是使用其他平台的云储存服务一般都是支持的。
要提高下载速度,就需要使用多线程下载,这里我是同时下载5个文件,小于1M的文件使用单线程下载,大于1M的文件使用多线程,我这边是每个文件开辟了十个线程,每个线程请求<文件长度/总线程数>的范围 ,每个线程把请求到的数据缓存到一个大小为10240的Byte数组中,储存满了或者传输完毕后,就把文件指针Seek到相应位置,写入文件流数据。
PS:惭愧的是一开始对服务器的接受请求和防御IP攻击的机制并不熟悉,采用了不断开辟线程请求Range为10240范围的内容的方式,进行大量的请求,发生了服务器误认为是IP攻击的乌龙。
若要支持断点续传。那么就需要实时更新已下载并写入文件中的数据信息,记录哪些文件已经下载完毕,哪些文件是正在下载的,并且正在下载的文件哪些部分已经下载好了,下次重新下载的时候只需要从未下载完成的部分开始即可。
文件完整性校验
在整体更新完成后,一般需要进行一个文件完整性校验,即为根据文件对照表中的信息,遍历表中文件,校验文件特征码是否匹配,此项检测通过后即可启动客户端。
关于Launcher的自更新
根据需求的不同,有些Launcher除了用于更新外,还肩负着展示产品信息的任务,所以有的时候会有对Launcher进行更新的要求,让Launcher在程序内自更新是不大现实的,因为会有文件占用问题,所以会需要一个外置的更新程序。
Launcher的自更新方式用的比较多的是额外带有一个Update执行程序,这个执行程序的功能和Launcher有些相似,整体流程也可以参照Launcher的更新机制,只是一个的作用是用于更新客户端,Update的作用是用于更新Launcher,若Update程序需要更新,可以由Launcher完成。
需要注意的是,Launcher的更新方式和客户端还是有一些区别的,客户端一般整体比较大,而且由Launcher进行更新和启动,所以用户首先会启动Launcher再启动客户端,所以客户端的更新是可以直接删除和覆盖原有文件的,但是Launcher作为入口,如果采用直接删除覆盖的方式,如果Update在更新过程中因为意外关闭, 那么将会造成Launcher文件缺失无法打开的情况,所以Update对Launcher的更新可以先把需要更新的文件下载到一个Temp文件夹内,下载完毕后再把Temp文件夹中的文件覆盖原有文件,最后删除需要移除的文件,这样可以把意外发生率降到最低。
这里我采用了一个比较取巧的方法,由于Update程序本身的体积比较小,所以我在Launcher检测到自身版本需要更新后,直接从服务器下载最新的Update程序,完成自更新后删除。
更新的整体流程大约为:
- 检测版本需要更新。
- 下载最新的Update程序并关闭Launcher。
- Update程序完成更新后,打开Launcher并关闭自身。
- Launcher检测版本为最新版后,删除残留的Update程序。
整体的更新流程图
The end.
如有出错还望指正。
若有更好的建议,可以在评论里留言讨论。
图片来自《黑暗之魂3》。