from:https://blog.csdn.net/woaitingting1985/article/details/72954652
一、C/S自動更新原理
?C/S程序自動升級是一個很重要的功能,原理其實很簡單,一般包含兩個程序一個是主程序,也就是除了升級功能以外的程序,另一個就是升級程序,常見的360,金山安全衛士都是這樣。
?主要包括以下幾點:?? 1 比較版本? 2下載文件? 3更新文件 4啟動主程序。但其中的需要注意的細節很多。?
  ? 一般服務端會有一個配置文件包含最新更新的文件信息的配置文件,當然這些更新信息也可以存到數據庫,或者其他地方。客戶端(也就是需要更新的那部分程序)也有一個配置文件包含客戶端版本信息,這些信息可以存到專門的一個配置文件中,或者是config文件中,沒有一定的規定,可以根據實際設計。
?? 在客戶端程序啟動時,先啟動更新程序通過比較本地版本和服務端最新的版本信息判斷是否有新版本,如果有可以直接下載,下載完成替換成功后并更新客戶端版本信息,啟動主程序。
? ? ?? ? ?? 缺點:如果更新速度由于更新的文件很大或者網速很慢,用戶不得不等待很長時間,直到下載完成或者下載失敗。
? ? ? ? ? ? 優點:處理完成后,啟動的直接就是更新后的程序。不會出現由于主程序在運行導致替換文件時提示文件在使用,不能替換之類的錯誤。
?? 另一種方法是, 在客戶端段程序啟動時,啟動更新程序,但更新程序不做版本判斷,到客戶端更新目錄下檢查有沒有下載的新版本,如果有就更新主程序并更新客戶端版本信息,然后啟動主程序,如果沒有就直接啟動主程序。由主程序判斷是否有新版本,并在后臺下載把文件放到客戶端更新目錄中,下載完成后,提示用戶退出主程序,重新啟動,在啟動時由更新程序并更新客戶端和客戶端版本信息。????
? ? ?? ? ?? 缺點:由于下載是在主程序的后臺運行,可能會影響主程序的處理速度。
? ? ? ? ? ? 優點:避免了由于下載導致用戶長時間的等待。
1 比較版本
? ??比較依據:
??? 可以通過文件的最后修改時間,或者使用文件版本作為比較依據,使用文件最后修改時間顯然不是標準的做法,但也沒有錯誤,但需要注意日期的格式一定要統一,避免日? 期格式不一致導致錯誤??梢允褂肍ileinfo類獲取最后修改時間,注意時間應該取服務器時間,編譯程序集的機器時間應該相同,否則可能導致混亂。
FIleInfo類官網參考
?? 使用文件版本作為標準,則每次修改時必須修改版本號,C#程序就是要修AssemblyInfo.cs文件中的內容了,多了一步,規范多了。Version類處理版本信息并比較。?
Assembly?thisAssem?=?Assembly.GetExecutingAssembly();???????AssemblyName?thisAssemName?=?thisAssem.GetName();???????Version?ver?=?thisAssemName.Version;??Version類官網參考
? 當然也有其他的方式,例如MD5校驗值比較,文件大小比較,之類的方法。不過個人認為文件大小缺陷很明顯,新版本文件就一定比舊文件大嗎?不一定吧。重構是可能變小的。
當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級文件不同,會更復雜,比較的信息也更多。
???獲取服務端版本信息:
??? 如果服務端的版本信息存在數據庫,直接讀取數據庫,就可以獲取。如果存在配置文件,則可以通過webservice方法獲取,或者請求一個網頁 通過Response.Write();的方式獲取信息,當然這兩種方式都要建立虛擬目錄或者網站。
2下載文件
??存儲位置:
???? 如果新版本的文件存在數據庫,就直接讀取數據庫,不過這種方式個人不建議使用,例如更新文件很大時性能不是很好。
??? 存在固定虛擬目錄的指定路徑下,不失為一種好的方式,但客戶端要下載,所以要注意一定要分配下載權限。
下載方式:
?? 直接向通過虛擬路徑發出請求,下載文件,由于虛擬路徑有下載權限,如果更新需要判斷是否有權限,例如要交費后才能下載則不好處理。
? 另一種方式是向一個網頁發送請求,傳遞不同的查詢字符串,網頁 通過Response.BinaryWrite();的方式下載文件,則可以判斷權限,當然麻煩一些是避免不了的。
下載文件代碼
Uri?uri?=?new?Uri(downFileUrl?+?localFileName);????????????????HttpWebRequest?request?=?(HttpWebRequest)WebRequest.Create(uri);????????????????request.Credentials?=?CredentialCache.DefaultCredentials;????????????????request.MaximumAutomaticRedirections?=?4;????????????????localFileName?=?Path.GetFileName(localFileName);????????????????using?(HttpWebResponse?response?=?(HttpWebResponse)request.GetResponse())????????????????{????????????????????Stream?receiveStream?=?response.GetResponseStream();????????????????????string?newPath?=?Path.Combine(tempFold,?localFileName);????????????????????using?(FileStream?fs?=?new?FileStream(newPath,?FileMode.Create))????????????????????{????????????????????????Byte[]?buffer?=?new?Byte[4096];????????????????????????int?bytesRead?=?receiveStream.Read(buffer,?0,?buffer.Length);????????????????????????while?(bytesRead?>?0){????????????????????????????fs.Write(buffer,?0,?bytesRead);????????????????????????????bytesRead?=?receiveStream.Read(buffer,?0,?buffer.Length);????????????????????????}????????????????????}????????????????????receiveStream.Close();????????????????}??3更新文件
??????更新類型:
?? ? 直接替換的,例如修改了bug,直接替換的。
?? ? 新增加的,例如新增加的功能做成了新的類庫。
??? 需要刪除的,例如有些功能由于重構或者使用了了新方法不需要的。
? ?? 需要執行的,例如寫注冊表,注冊COM組件的。
???? 每一種處理方式都不一樣,需要根據類型分開處理
? ?? 缺點:升級后,沒辦法取消升級,像windows的補丁程序可以安裝,可以卸載的原理,目前還沒有研究明白,希望知道的牛人指導。
??? 當然也可以簡單的先卸載,再安裝,對于配置文件之類的信息特殊處理一下也可以。
?? 當然如果考慮客戶端有不同的版本,都需要升級到最新的版本,顯然不同的版本對應的升級文件不同,會更復雜,但基本原理卻不變。
4啟動主程序
??主程序路徑的獲取:
?? 相對路徑?? 主程序,更新程序,都使用相對路徑,缺點是一旦相對路徑確定后,后續的更新就不能更改這種目錄關系。
? 注冊表? 路徑都存入注冊表,需要時通過注冊表交互,主程序寫注冊表,更新程序讀取注冊表,缺點是讀寫注冊表需要權限,寫的路徑也要固定,后續的更新不能改變寫在注冊表中的位置,也就是注冊表路徑。
運行程序代碼
?
private?static?void?RunFile(string?dir,?string?localFileName){????????????string?info?=?"運行程序"?+?localFileName;????????????try{????????????????if?(File.Exists(Path.Combine(dir,?localFileName))){????????????????????Process?myProcess?=?new?Process();????????????????????ProcessStartInfo?psi?=?new?ProcessStartInfo();????????????????????psi.FileName?=?localFileName;????????????????????psi.WorkingDirectory?=?dir;????????????????????psi.UseShellExecute?=?false;????????????????????psi.RedirectStandardError?=?true;????????????????????psi.CreateNoWindow?=?true;????????????????????psi.RedirectStandardOutput?=?true;????????????????????psi.WindowStyle?=?ProcessWindowStyle.Hidden;????????????????????myProcess.StartInfo?=?psi;????????????????????myProcess.Start();??????????????????????string?error?=?myProcess.StandardError.ReadToEnd();????????????????????string?output?=?myProcess.StandardOutput.ReadToEnd();????????????????????myProcess.WaitForExit();????????????????????myProcess.Close();????????????????????if?(error?!=?string.Empty){?????????????????????Log.Write("StandardError:"?+?error);????????????????????}????????????????????if?(output?!=?string.Empty){????????????????????????Log.Write("StandardOutput:"?+?output);????????????????????}????????????????????Log.LogProcessEnd(info);????????????????}????????????}????????????catch?(Exception?ex){???????????????Log.Write(info?+?"出錯");???????????????Log.LogException(ex);????????????????throw?ex;????????????}????????}????} ?
二、使用HttpWebRequest自動更新客戶端更新客戶端應用程序,對于采用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 plaincopy?
import?javax.swing.*;??import?java.awt.*;??import?java.net.*;??import?java.io.*;????public?class?CheckUpdate?extends?JFrame?{??????JFrame?c?=?this;????????public?CheckUpdate()?{????????????????????setAttb();????????????JLabel?title?=?new?JLabel("正在檢查網絡上的更新資源");??????????this.add(title,?BorderLayout.NORTH);??????????JTextArea?msg?=?new?JTextArea();??????????this.add(msg,?BorderLayout.CENTER);??????????JLabel?process?=?new?JLabel();??????????this.add(process,?BorderLayout.SOUTH);??????????????????????????????new?Check(msg,?process).start();??????}????????private?class?Check?extends?Thread?{????????????????????private?boolean?isUpdated?=?false;????????????????????String?netVersion;????????????????????String?LocalVerFileName?=?"ver.txt";??????????????????????private?JTextArea?msg;??????????private?JLabel?process;????????????public?Check(JTextArea?msg,?JLabel?process)?{??????????????this.msg?=?msg;??????????????this.process?=?process;??????????}????????????public?void?run()?{????????????????????????????String?versionUrl?=?"http://XXX.XXX.XXX/AutoUpdate/ver";?????????????????????????URL?url?=?null;??????????????InputStream?is?=?null;??????????????InputStreamReader?isr?=?null;??????????????BufferedReader?netVer?=?null;??????????????????????????????try?{??????????????????url?=?new?URL(versionUrl);??????????????????is?=?url.openStream();??????????????????isr?=?new?InputStreamReader(is);????????????????????netVer?=?new?BufferedReader(isr);??????????????????String?netVerStr?=?netVer.readLine();??????????????????String?localVerStr?=?getNowVer();????????????????????if?(netVerStr.equals(localVerStr))?{??????????????????????msg.append("當前文件是最新版本\n");??????????????????????isUpdated?=?false;??????????????????}?else?{??????????????????????msg.append("存在更新文件,現在開始更新\n");??????????????????????isUpdated?=?true;??????????????????????netVersion?=?netVerStr;??????????????????}????????????????}?catch?(MalformedURLException?ex)?{??????????????}?catch?(IOException?ex)?{??????????????}?finally?{????????????????????????????????????try?{??????????????????????netVer.close();??????????????????????isr.close();??????????????????????is.close();??????????????????}?catch?(IOException?ex1)?{??????????????????}??????????????}??????????????????????????????if?(isUpdated)?{????????????????????????????????????File?oldFile?=?new?File("client.exe");????????????????????????????????????File?newFile?=?new?File("temp.exe");??????????????????????????????????????????????????????String?updateUrl?=??????????????????????????"http://XXX.XXX.XXX/downloads/simpkle.exe";????????????????????HttpURLConnection?httpUrl?=?null;??????????????????BufferedInputStream?bis?=?null;??????????????????FileOutputStream?fos?=?null;????????????????????try?{????????????????????????????????????????????url?=?new?URL(updateUrl);??????????????????????httpUrl?=?(HttpURLConnection)?url.openConnection();????????????????????????httpUrl.connect();????????????????????????byte[]?buffer?=?new?byte[1024];????????????????????????int?size?=?0;????????????????????????is?=?httpUrl.getInputStream();??????????????????????bis?=?new?BufferedInputStream(is);??????????????????????fos?=?new?FileOutputStream(newFile);????????????????????????msg.append("正在從網絡上下載新的更新文件\n");??????????????????????????????????????????????try?{??????????????????????????int?flag?=?0;??????????????????????????int?flag2?=?0;??????????????????????????while?((size?=?bis.read(buffer))?!=?-1)?{????????????????????????????????????????????????????????????fos.write(buffer,?0,?size);??????????????????????????????fos.flush();??????????????????????????????????????????????????????????????if?(flag2?==?99)?{??????????????????????????????????flag2?=?0;??????????????????????????????????process.setText(process.getText()?+?".");??????????????????????????????}??????????????????????????????flag2++;??????????????????????????????flag++;??????????????????????????????if?(flag?>?99?*?50)?{??????????????????????????????????flag?=?0;??????????????????????????????????process.setText("");??????????????????????????????}??????????????????????????}??????????????????????}?catch?(Exception?ex4)?{??????????????????????????System.out.println(ex4.getMessage());??????????????????????}????????????????????????msg.append("\n文件下載完成\n");??????????????????????????????????????????????CopyFile(oldFile,newFile);??????????????????????????????????????????????????????????????????UpdateLocalVerFile();????????????????????}?catch?(MalformedURLException?ex2)?{??????????????????}?catch?(IOException?ex)?{??????????????????????msg.append("文件讀取錯誤\n");??????????????????}?finally?{??????????????????????try?{??????????????????????????fos.close();??????????????????????????bis.close();??????????????????????????is.close();??????????????????????????httpUrl.disconnect();??????????????????????}?catch?(IOException?ex3)?{??????????????????????}??????????????????}??????????????}??????????????????????????????try?{??????????????????msg.append("啟動應用程序");??????????????????Thread.sleep(500);??????????????????Process?p?=?Runtime.getRuntime().exec("client.exe");??????????????}?catch?(IOException?ex5)?{??????????????}?catch?(InterruptedException?ex)?{??????????????}??????????????????????????????????????????System.exit(0);??????????}????????????private?void?CopyFile(File?oldFile,?File?newFile)?{??????????????FileInputStream?in?=?null;??????????????FileOutputStream?out?=?null;????????????????????????????try?{??????????????????if(oldFile.exists()){??????????????????????oldFile.delete();??????????????????}??????????????????in?=?new?FileInputStream(newFile);??????????????????out?=?new?FileOutputStream(oldFile);????????????????????byte[]?buffer?=?new?byte[1024?*?5];??????????????????int?size;??????????????????while?((size?=?in.read(buffer))?!=?-1)?{??????????????????????out.write(buffer,?0,?size);??????????????????????out.flush();??????????????????}??????????????}?catch?(FileNotFoundException?ex)?{??????????????}?catch?(IOException?ex)?{??????????????}?finally?{??????????????????try?{??????????????????????out.close();??????????????????????in.close();??????????????????}?catch?(IOException?ex1)?{??????????????????}??????????????}????????????}????????????private?void?UpdateLocalVerFile()?{????????????????????????????FileWriter?verOS?=?null;??????????????BufferedWriter?bw?=?null;??????????????try?{??????????????????verOS?=?new?FileWriter(LocalVerFileName);????????????????????bw?=?new?BufferedWriter(verOS);??????????????????bw.write(netVersion);??????????????????bw.flush();????????????????}?catch?(IOException?ex)?{??????????????}?finally?{??????????????????try?{??????????????????????bw.close();??????????????????????verOS.close();??????????????????}?catch?(IOException?ex1)?{??????????????????}??????????????}??????????}????????????private?String?getNowVer()?{????????????????????????????File?verFile?=?new?File(LocalVerFileName);????????????????FileReader?is?=?null;??????????????BufferedReader?br?=?null;??????????????????????????????try?{??????????????????is?=?new?FileReader(verFile);????????????????????br?=?new?BufferedReader(is);??????????????????String?ver?=?br.readLine();????????????????????return?ver;??????????????}?catch?(FileNotFoundException?ex)?{??????????????????msg.append("本地版本文件未找到\n");??????????????}?catch?(IOException?ex)?{??????????????????msg.append("本地版本文件讀取錯誤\n");??????????????}?finally?{????????????????????????????????????try?{??????????????????????br.close();??????????????????????is.close();??????????????????}?catch?(IOException?ex1)?{??????????????????}??????????????}??????????????return?"";??????????}??????}??????????private?void?setAttb()?{????????????????????this.setTitle("Auto?Update");??????????this.setSize(200,?150);??????????this.setLayout(new?BorderLayout());??????????this.setDefaultCloseOperation(EXIT_ON_CLOSE);??????????????????????Dimension?screenSize?=?Toolkit.getDefaultToolkit().getScreenSize();??????????Dimension?frameSize?=?this.getSize();??????????if?(frameSize.height?>?screenSize.height)?{??????????????frameSize.height?=?screenSize.height;??????????}??????????if?(frameSize.width?>?screenSize.width)?{??????????????frameSize.width?=?screenSize.width;??????????}??????????this.setLocation((screenSize.width?-?frameSize.width)?/?2,???????????????????????????(screenSize.height?-?frameSize.height)?/?2);??????}????????public?static?void?main(String[]?args)?{??????????CheckUpdate?checkupdate?=?new?CheckUpdate();??????????checkupdate.setVisible(true);??????}??} ?
版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/woaitingting1985/article/details/72954652
                            
總結
                            
                                以上是生活随笔為你收集整理的客户端程序自动更新(升级)的方式的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。