1. 程式人生 > >客戶端程式自動更新(升級)的方式

客戶端程式自動更新(升級)的方式

一、C/S自動更新原理

 C/S程式自動升級是一個很重要的功能,原理其實很簡單,一般包含兩個程式一個是主程式,也就是除了升級功能以外的程式,另一個就是升級程式,常見的360,金山安全衛士都是這樣。

 主要包括以下幾點:   1 比較版本  2下載檔案  3更新檔案 4啟動主程式。但其中的需要注意的細節很多。 

    一般服務端會有一個配置檔案包含最新更新的檔案資訊的配置檔案,當然這些更新資訊也可以存到資料庫,或者其他地方。客戶端(也就是需要更新的那部分程式)也有一個配置檔案包含客戶端版本資訊,這些資訊可以存到專門的一個配置檔案中,或者是config檔案中,沒有一定的規定,可以根據實際設計。

   在客戶端程式啟動時,先啟動更新程式通過比較本地版本和服務端最新的版本資訊判斷是否有新版本,如果有可以直接下載,下載完成替換成功後並更新客戶端版本資訊,啟動主程式。

            缺點:如果更新速度由於更新的檔案很大或者網速很慢,使用者不得不等待很長時間,直到下載完成或者下載失敗。

            優點:處理完成後,啟動的直接就是更新後的程式。不會出現由於主程式在執行導致替換檔案時提示檔案在使用,不能替換之類的錯誤。

   另一種方法是, 在客戶端段程式啟動時,啟動更新程式,但更新程式不做版本判斷,到客戶端更新目錄下檢查有沒有下載的新版本,如果有就更新主程式並更新客戶端版本資訊,然後啟動主程式,如果沒有就直接啟動主程式。由主程式判斷是否有新版本,並在後臺下載把檔案放到客戶端更新目錄中,下載完成後,提示使用者退出主程式,重新啟動,在啟動時由更新程式並更新客戶端和客戶端版本資訊。    

            缺點:由於下載是在主程式的後臺執行,可能會影響主程式的處理速度。

            優點:避免了由於下載導致使用者長時間的等待。

1 比較版本

    比較依據:

    可以通過檔案的最後修改時間,或者使用檔案版本作為比較依據,使用檔案最後修改時間顯然不是標準的做法,但也沒有錯誤,但需要注意日期的格式一定要統一,避免日  期格式不一致導致錯誤。可以使用Fileinfo類獲取最後修改時間,注意時間應該取伺服器時間,編譯程式集的機器時間應該相同,否則可能導致混亂。

   使用檔案版本作為標準,則每次修改時必須修改版本號,C#程式就是要修AssemblyInfo.cs檔案中的內容了,多了一步,規範多了。Version類處理版本資訊並比較。 

  1. Assembly thisAssem = Assembly.GetExecutingAssembly();  
  2.      AssemblyName thisAssemName = thisAssem.GetName();  
  3.      Version ver = thisAssemName.Version;  

  當然也有其他的方式,例如MD5校驗值比較,檔案大小比較,之類的方法。不過個人認為檔案大小缺陷很明顯,新版本檔案就一定比舊檔案大嗎?不一定吧。重構是可能變小的。

當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級檔案不同,會更復雜,比較的資訊也更多。

   獲取服務端版本資訊:

    如果服務端的版本資訊存在資料庫,直接讀取資料庫,就可以獲取。如果存在配置檔案,則可以通過webservice方法獲取,或者請求一個網頁 通過Response.Write();的方式獲取資訊,當然這兩種方式都要建立虛擬目錄或者網站。

2下載檔案

  儲存位置:

     如果新版本的檔案存在資料庫,就直接讀取資料庫,不過這種方式個人不建議使用,例如更新檔案很大時效能不是很好。

    存在固定虛擬目錄的指定路徑下,不失為一種好的方式,但客戶端要下載,所以要注意一定要分配下載許可權。

下載方式:

   直接向通過虛擬路徑發出請求,下載檔案,由於虛擬路徑有下載許可權,如果更新需要判斷是否有許可權,例如要交費後才能下載則不好處理。

  另一種方式是向一個網頁傳送請求,傳遞不同的查詢字串,網頁 通過Response.BinaryWrite();的方式下載檔案,則可以判斷許可權,當然麻煩一些是避免不了的。

下載檔案程式碼

  1. Uri uri = new Uri(downFileUrl + localFileName);  
  2.               HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);  
  3.               request.Credentials = CredentialCache.DefaultCredentials;  
  4.               request.MaximumAutomaticRedirections = 4;  
  5.               localFileName = Path.GetFileName(localFileName);  
  6.               using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())  
  7.               {  
  8.                   Stream receiveStream = response.GetResponseStream();  
  9.                   string newPath = Path.Combine(tempFold, localFileName);  
  10.                   using (FileStream fs = new FileStream(newPath, FileMode.Create))  
  11.                   {  
  12.                       Byte[] buffer = new Byte[4096];  
  13.                       int bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  14.                       while (bytesRead > 0){  
  15.                           fs.Write(buffer, 0, bytesRead);  
  16.                           bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  17.                       }  
  18.                   }  
  19.                   receiveStream.Close();  
  20.               }  

3更新檔案

      更新型別:

     直接替換的,例如修改了bug,直接替換的。

     新增加的,例如新增加的功能做成了新的類庫。

    需要刪除的,例如有些功能由於重構或者使用了了新方法不需要的。

     需要執行的,例如寫登錄檔,註冊COM元件的。

     每一種處理方式都不一樣,需要根據型別分開處理

     缺點:升級後,沒辦法取消升級,像windows的補丁程式可以安裝,可以解除安裝的原理,目前還沒有研究明白,希望知道的牛人指導。

    當然也可以簡單的先解除安裝,再安裝,對於配置檔案之類的資訊特殊處理一下也可以。

   當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級檔案不同,會更復雜,但基本原理卻不變。

4啟動主程式

  主程式路徑的獲取:

   相對路徑   主程式,更新程式,都使用相對路徑,缺點是一旦相對路徑確定後,後續的更新就不能更改這種目錄關係。

  登錄檔  路徑都存入登錄檔,需要時通過登錄檔互動,主程式寫登錄檔,更新程式讀取登錄檔,缺點是讀寫登錄檔需要許可權,寫的路徑也要固定,後續的更新不能改變寫在登錄檔中的位置,也就是登錄檔路徑。

執行程式程式碼

  1. private static void RunFile(string dir, string localFileName){  
  2.           string info = "執行程式" + localFileName;  
  3.           try{  
  4.               if (File.Exists(Path.Combine(dir, localFileName))){  
  5.                   Process myProcess = new Process();  
  6.                   ProcessStartInfo psi = new ProcessStartInfo();  
  7.                   psi.FileName = localFileName;  
  8.                   psi.WorkingDirectory = dir;  
  9.                   psi.UseShellExecute = false;  
  10.                   psi.RedirectStandardError = true;  
  11.                   psi.CreateNoWindow = true;  
  12.                   psi.RedirectStandardOutput = true;  
  13.                   psi.WindowStyle = ProcessWindowStyle.Hidden;  
  14.                   myProcess.StartInfo = psi;  
  15.                   myProcess.Start();  
  16.                   string error = myProcess.StandardError.ReadToEnd();  
  17.                   string output = myProcess.StandardOutput.ReadToEnd();  
  18.                   myProcess.WaitForExit();  
  19.                   myProcess.Close();  
  20.                   if (error != string.Empty){  
  21.                    Log.Write("StandardError:" + error);  
  22.                   }  
  23.                   if (output != string.Empty){  
  24.                       Log.Write("StandardOutput:" + output);  
  25.                   }  
  26.                   Log.LogProcessEnd(info);  
  27.               }  
  28.           }  
  29.           catch (Exception ex){  
  30.              Log.Write(info + "出錯");  
  31.              Log.LogException(ex);  
  32.               throw ex;  
  33.           }  
  34.       }  
  35.   }  
更新客戶端應用程式,對於採用Socket實現的,可以採用Socket從伺服器端下載;對於其它方式, 一般可以採用以HttpWebRequest/WebClient的方式予以下載,但WebClient在下載的時候無法看到下載進度,因此,使用HttpWebRequest 下載檔案,根據讀取到的流長度,確定當前下載的資料量,以反應當前下載的進度。

    找了半天也沒有找到在那兒可以上傳檔案,所以只好將檔案上傳到部落格園。

下載地址:http://www.cnblogs.com/Files/bluedream/Update.rar

說明:

在客戶端,使用者實際執行的是更新程式,在更新程式檢查完成後,再執行實際的客戶端。當然,這個對使用者是隱藏的。

1、DownloadFile.cs: 使用HttpWebRequest下載指定URL的檔案

2、EventArgs.cs:委託及事件

3、FormUpdate.cs:下載時的UI處理

4、Global.cs和UpdateUtility.cs通用處理函式庫

5、Client.cs:更新客戶端的應用程式

6、Update檔案:客戶端更新配置檔案,在更新時,應用程式先讀取Update檔案,然後根據Update檔案中儲存的遠端伺服器URL地址,讀取遠端更新檔案,接著比較遠端伺服器配置檔案與本地配置檔案及本地檔案相比較,確定更新列表,然後下載檔案;下載完成後,覆蓋本地檔案;再刪除臨時檔案;最後呼叫本地配置檔案指定的更新完成後應執行的應用程式。

三、JAVA自動更新客戶端

最近由於一個工程需要做應用程式啟動時,自動更新的專案
在GOOGLE上找了半天也沒見到什麼比較好的辦法
自己動手寫了一個通過版本號檢查網路上是不是存在新的更新檔案,並自動通過HTTP下載檔案的程式
希望對正在找此類程式的朋友有幫助

本地檔案需要一個ver.txt  此檔案內容為本地軟體版本號
網路上我直接在一個頁面上打印出網路存在的版本號
例如,這個例子裡,我在 http://XXX.XXX.XXX/AutoUpdate/ver  這裡直接打印出版本號

原始檔:http://211.136.109.100/beiouwolf/AutoUpdate.rar

[java] view plain copy  print?
  1. import javax.swing.*;  
  2. import java.awt.*;  
  3. import java.net.*;  
  4. import java.io.*;  
  5. publicclass CheckUpdate extends JFrame {  
  6.     JFrame c = this;  
  7.     public CheckUpdate() {  
  8.         //設定窗體屬性
  9.         setAttb();  
  10.         JLabel title = new JLabel("正在檢查網路上的更新資源");  
  11.         this.add(title, BorderLayout.NORTH);  
  12.         JTextArea msg = new JTextArea();  
  13.         this.add(msg, BorderLayout.CENTER);  
  14.         JLabel process = new JLabel();  
  15.         this.add(process, BorderLayout.SOUTH);  
  16.         //啟動更新執行緒
  17.         new Check(msg, process).start();  
  18.     }  
  19.     privateclass Check extends Thread {  
  20.         //標識,是否存在新的更新檔案
  21.         privateboolean isUpdated = false;  
  22.         //儲存最新的版本
  23.         String netVersion;  
  24.         //本地版本檔名
  25.         String LocalVerFileName = "ver.txt";  
  26.         //顯示資訊
  27.         private JTextArea msg;  
  28.         private JLabel process;  
  29.         public Check(JTextArea msg, JLabel process) {  
  30.             this.msg = msg;  
  31.             this.process = process;  
  32.         }  
  33.         publicvoid r