休息日,没事想放松下,感受一下大众瞩目的LOL,可惜刚打开就提示需要更新,一看要更新好几百m,顿时郁闷之极,就为了玩个游戏,每个星期都得更新个半天.然后无聊了半天等待下载,发现闲着
也是闲着,研究学习了,似乎LOL也是.net框架的,顺便就学习下自动更新吧. 1.自动更新,首先要比较服务端和客户端相关文件,具体比对哪些内容呢?修改时间,文件大小,文件内容等等,比对内容很多,这个时候就想到了用md5比较,具体实现:
public static byte[] GetFileMd5(this FileInfo fileInfo) { using (var fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var md5Provider = new MD5CryptoServiceProvider()) { return md5Provider.ComputeHash(fs); } } }
2.文件md5后就可以比较两边的差异了,可以通过wcf连接,具体请参考
http://www.cnblogs.com/gavinhuang/archive/2013/03/30/2991060.html创建服务.
获取服务端md5,然后比较,具体实现:
var needDownload = false; var localMd5 = new FileInfo(localFullPath).GetFileMd5(); var updateClient = new AutoUpdateClient(EndpointName, endpointAddress); var remoteMd5 = updateClient.GetFileMd5(relativePath); needDownload = !localMd5.SequenceEqual(remoteMd5);
服务端具体实现:
public byte[] GetFileMd5(string fileName) { var beforeCount = Interlocked.Increment(ref _refreshQuests); var root = Settings.Default.VersionDirectory ; var fullPath = Path.Combine(Settings.Default.VersionDirectory, fileName); if (!File.Exists(fullPath)) { throw new FaultException<FileNotFoundFault>(new FileNotFoundFault { FileName = fileName, }); } var fileInfo = new FileInfo(fileName); var re = fileInfo.GetFileMd5(); return re ; } public IAsyncResult BeginDownloadFile(string fileName, long position, int numBytes, AsyncCallback callback, object state) { var fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName); if (!File.Exists(fullPath)) { throw new FaultException<FileNotFoundFault>(new FileNotFoundFault { FileName = fileName, }); } return new FileTransferAsyncResult(fullPath, position, numBytes, callback, state); } public RemoteFileInfo EndDownloadFile(IAsyncResult ar) { return ((FileTransferAsyncResult)ar).EndInvoke(); }
同时定义FileTransferAsyncResult类继承Wintellect.Threading.AsyncProgModel.AsyncResult<RemoteFileInfo>
public FileTransferAsyncResult(string fileName, long position, int numBytes, AsyncCallback callback, object state) : base(callback, state) { _buffer = new byte[numBytes]; _stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous); _stream.Position = position; _stream.BeginRead(_buffer, 0, _buffer.Length, Wintellect.Threading.AsyncProgModel.AsyncResult<RemoteFileInfo>.GetAsyncCallbackHelper(), this); } protected override RemoteFileInfo OnCompleteOperation(IAsyncResult ar) { int bytesRead = _stream.EndRead(ar); long nextPosition = _stream.Position; long totalLength = _stream.Length; _stream.Close(); return new RemoteFileInfo() { Data = _buffer, BytesLength = bytesRead, NextPosition = nextPosition, TotalLength = totalLength }; }
最后客户端连接
private void DownLoad() { bool needDownload = true; var localPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Test.txt"); var client = new UpdateClient("netTcpBinding"); int _downloadingRequests = 0; var bufferSize = 4096; if (File.Exists(localPath)) { var localMd5 = new FileInfo(localPath).GetFileMd5(); var remoteMd5 = client.GetFileMd5("Test.txt"); needDownload = !localMd5.SequenceEqual(remoteMd5); } if (needDownload) { using (var fs = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.Write, bufferSize, FileOptions.Asynchronous)) { long position = 0; long writtenBytes = 0; RemoteFileInfo info = null; do { Interlocked.Increment(ref _downloadingRequests); info = client.DownloadFile("Test.txt", 0, bufferSize); Interlocked.Decrement(ref _downloadingRequests); position = info.NextPosition; fs.Write(info.Data, 0, info.BytesLength); writtenBytes += info.BytesLength; } while (info.BytesLength != position); } client.Close(); } }
这样自制的简易更新,或者上传,下载小程序做好了,当然还有许多地方可以优化比如进度条,比如同时更新多个等.