版本自动更新程序及3种实现策略程序下载(附源码)

http://www.vjsdn.com/bbs/bbsTopicDetails.aspx?pid=611


版本自动更新程序及3种实现策略(一)文档及UML图


版本自动更新程序及3种实现策略(二)下载器实现 

程序界面及系统设置
贴图图片
图1-版本升级程序服务器端设置
1. 服务器端程序发布URL地址,该参数用于Web下载器连接的url地址。
2. 服务器端程序发布目录,用于tcp/ip下载器下载的目录。
3. 服务器端程序共享目录,用于Lan下载器下载的目录.
以前3个参数跟据选择的下载器类型做相应设置。

贴图图片
图2-本机配置
本地程序发布目录:用于任一下载器下载文件后存放文件的目录。

贴图图片
图3-下载器设置(更新参数设置,未改名)
选择三种下载器中任何一种作为当前下载器。

贴图图片
图4-Tcp/Ip下载器服务器程序.
当您选择Tcp/Ip下载器升级程序,请先运行服务器端程序。
 
贴图图片
图5-版本自动升级程序主界面

运行程序前先要配置系统参数,配置文件保存在程序运行目录下的upgrader.dat文件。参考上面的所介绍的系统设置界面。跟据选择的下载器类型作相应配置。

如出现以下提示,说明您还没有配置程序目录下无upgrader.dat文件.
贴图图片
图6-没有配置文件提示窗体

服务器程序发布目录结构如下图:
 贴图图片
图7-服务器程序发布目录结构

D:\Shared\是服务器上的目录,该目录存放最新版本文件及XmlServerFiles.xml 文件清单。
清单文件可以通过枚举目录下包括子目录下所有文件自动生成,下次更新版本时只需调整某几项内容。

XmlServerFiles.xml 文件内容

<?xml version="1.0" encoding="utf-8" ?>
<Upgrader>
<description>服务器端文件清单</description>
<Application>
<!--程序最新版本发布时间-->
<LastUpdateTime value="4/26/2007 10:30:32 AM" />
<!--版本号-->
<Version value="1.2.1" />
</Application>
<Files>
<File fullPath=".\Web3Layers.rar" fileName="Web3Layers.rar" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\ip_setup.txt" fileName="ip_setup.txt" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\a.png" fileName="a.png" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\mdimain2.png" fileName="mdimain2.png" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\KAV8.0-Key.R00" fileName="KAV8.0-Key.R00" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\crossthread.png" fileName="crossthread.png" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\newfolder\kav.rar" fileName="kav.rar" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\a\crossthread.png" fileName="crossthread.png" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\VJSDN.Tech.AutoUpgrader.exe" fileName="VJSDN.Tech.AutoUpgrader.exe" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\VJSDN.Tech.AutoUpgradeServer.exe" fileName="VJSDN.Tech.AutoUpgradeServer.exe" lastModify="4/26/2009 9:53:23 AM" />
<File fullPath=".\VJSDN.Tech.AutoUpgraderLib.dll" fileName="VJSDN.Tech.AutoUpgraderLib.dll" lastModify="4/26/2009 9:53:23 AM" />
</Files>
</Upgrader>


AppSettings.cs 系统参数代码实现(序列化对象保存为文件)

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace VJSDN.Tech.AutoUpgraderLib
{
    /// <summary> 
    /// 系统参数。序列化对象保存为文件. 
    /// </summary> 
   [Serializable]
    public  class AppSettings
   {
       private  string _ServerSharedFolder = "";
       private  string _ServerIP = "";
       private  int _ServerPort = 0;
       private  string _ServerFilesXml = "";
       private  string _ServerPublishFolder = "";  //用于tcp/ip下载.服务器上程序文件的发布目录。 
       private  string _ServerPublishUrl = "";
       private  string _ClientSaveFolder = "";
       private  string _ClientFilesXml = "";
       private  int _DownloaderType = 0;
      
      
       private  static AppSettings _instance =  null;
      
       /// <summary> 
       /// 系统参数实例。 
       /// </summary> 
       public  static AppSettings Instance
      {
          get
         {
             if (_instance ==  null) CreateDefault();
             return _instance;
         }
      }
      
       private  static  void CreateDefault()
      {
         _instance =  new AppSettings();
         _instance.ServerFilesXml = "XmlServerFiles.xml";
         _instance.ServerSharedFolder = @"\\192.168.1.2\Shared";
         _instance.ServerPublishUrl = "http://www.vjsdn.com/UserUpload";
         _instance.ServerPublishFolder = @"d:\mypublish\autoupgrader";
         _instance.ServerIP = "192.168.1.1";
         _instance.ServerPort = 12345;
         _instance.DownloaderType = ( int)DownloadType.Intranet;
         _instance.ClientFilesXml = "XmlClientFiles.xml";
         _instance.ClientSaveFolder = @"c:\yourfolder\newversion";
         
      }
      
       public  static  bool HasSetting()
      {
          string file = Application.StartupPath + @"\upgrader.dat";
          return File.Exists(file);
      }
      
       /// <summary> 
       /// 读取参数 
       /// </summary> 
       public  static  void Read()
      {
          string file = Application.StartupPath + @"\upgrader.dat";
          if (File.Exists(file))
         {
            FileStream fs = File.Open(file, FileMode.OpenOrCreate, FileAccess.Read);
             byte[] bs =  new  byte[fs.Length];
             int len = fs.Read(bs, 0, bs.Length);
             if (len > 0)
            {
                object o = ZipObject.DecompressionObject(bs);
               _instance = (AppSettings)o;
            }
            fs.Close();
         }
      }
      
       /// <summary> 
       /// 保存参数 
       /// </summary> 
       public  static  void Write()
      {
          string file = Application.StartupPath + @"\upgrader.dat";
         FileStream fs = File.Open(file, FileMode.OpenOrCreate, FileAccess.Write);
          byte[] bs = ZipObject.CompressionObject(_instance);
         fs.Write(bs, 0, bs.Length);
         fs.Flush();
         fs.Close();
      }
      
       /// <summary> 
       /// 用于内部网络直接Copy的共享目录。 
       /// </summary> 
       public  string ServerSharedFolder {  get {  return _ServerSharedFolder; }  set { _ServerSharedFolder = value; } }
      
       /// <summary> 
       /// 用于Tcp/Ip下载的服务器IP。 
       /// </summary> 
       public  string ServerIP {  get {  return _ServerIP; }  set { _ServerIP = value; } }
      
       /// <summary> 
       /// 用于Tcp/Ip下载的服务器端口 
       /// </summary> 
       public  int ServerPort {  get {  return _ServerPort; }  set { _ServerPort = value; } }
      
       /// <summary> 
       /// 下载类型(策略) 
       /// </summary> 
       public  int DownloaderType {  get {  return _DownloaderType; }  set { _DownloaderType = value; } }
      
       /// <summary> 
       /// 发布在服务器上的程序Url地址。如:http://www.vjsdn.com/publish 
       /// </summary> 
       public  string ServerPublishUrl {  get {  return _ServerPublishUrl; }  set { _ServerPublishUrl = value; } }
      
       /// <summary> 
       /// 用于tcp/ip下载.服务器上程序文件的发布目录 
       /// </summary> 
       public  string ServerPublishFolder {  get {  return _ServerPublishFolder; }  set { _ServerPublishFolder = value; } }
      
       /// <summary> 
       /// 客户端文件目录,下载文件保存的目录。如:c:\myapp 
       /// </summary> 
       public  string ClientSaveFolder {  get {  return _ClientSaveFolder; }  set { _ClientSaveFolder = value; } }
      
       /// <summary> 
       /// 客户机器上的文件列表 
       /// </summary> 
       public  string ClientFilesXml {  get {  return _ClientFilesXml; }  set { _ClientFilesXml = value; } }
      
       /// <summary> 
       /// 服务器上的文件列表 
       /// </summary> 
       public  string ServerFilesXml {  get {  return _ServerFilesXml; }  set { _ServerFilesXml = value; } }
      
   }
}

Common.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.IO.Compression;

namespace VJSDN.Tech.AutoUpgraderLib
{
    public  class Common
   {
       //字符转日期 
       public  static DateTime StrToDate( string date)
      {
         DateTime ret = DateTime.MinValue;
          if (DateTime.TryParse(date,  out ret))
          return ret;
          else
          return DateTime.MinValue;
      }
   }
   
    /// <summary> 
    /// 压缩解压object 
    /// </summary> 
    public  class ZipObject
   {
       public  static  byte[] CompressionObject( object DataOriginal)
      {
          if (DataOriginal ==  nullreturn  null;
         BinaryFormatter bFormatter =  new BinaryFormatter();
         MemoryStream mStream =  new MemoryStream();
         bFormatter.Serialize(mStream, DataOriginal);
          byte[] bytes = mStream.ToArray();
         MemoryStream oStream =  new MemoryStream();
         DeflateStream zipStream =  new DeflateStream(oStream, CompressionMode.Compress);
         zipStream.Write(bytes, 0, bytes.Length);
         zipStream.Flush();
         zipStream.Close();
          return oStream.ToArray();
      }
      
       public  static  object DecompressionObject( byte[] bytes)
      {
          if (bytes ==  nullreturn  null;
         MemoryStream mStream =  new MemoryStream(bytes);
         mStream.Seek(0, SeekOrigin.Begin);
         DeflateStream unZipStream =  new DeflateStream(mStream, CompressionMode.Decompress,  true);
          object dsResult =  null;
         BinaryFormatter bFormatter =  new BinaryFormatter();
         dsResult = ( object)bFormatter.Deserialize(unZipStream);
          return dsResult;
      }
   }
}

FileView.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Threading;

namespace VJSDN.Tech.AutoUpgraderLib
{
    /// <summary> 
    /// 文件视图,文件结构以树形展示。 
    /// </summary> 
    public  class FileView
   {
       private XmlLoader _xml =  null;
       private ToolStripProgressBar _progress =  null;
      
       public FileView(XmlLoader xml, ToolStripProgressBar progress)
      {
         _xml = xml;
         _progress = progress;
      }
      
       //将xml转换为TreeView 
       public  void LoadTreeViewServer(TreeView treeView)
      {
         treeView.Nodes.Clear();
         XmlNode node = _xml.XML.SelectSingleNode("Upgrader/Files");
          if (node ==  nullthrow  new Exception("找不到xml文件的Upgrader/Files结点!");
         _progress.Maximum = node.ChildNodes.Count + 1;
         _progress.Minimum = 1;
         _progress.Value = 1;
         
          foreach (XmlNode n  in node.ChildNodes)
         {
            CreateNode(treeView, n,  null);
            _progress.Value++;
         }
      }
      
       //将xml转换为TreeView.同时与服务器匹配 
       public  void LoadTreeViewClient(TreeView treeView, XmlLoader server)
      {
         treeView.Nodes.Clear();
         XmlNode node = _xml.XML.SelectSingleNode("Upgrader/Files");
          if (node ==  nullthrow  new Exception("找不到xml文件的Upgrader/Files结点!");
         _progress.Maximum = node.ChildNodes.Count + 1;
         _progress.Minimum = 1;
         _progress.Value = 1;
         
          foreach (XmlNode n  in node.ChildNodes)
         {
            CreateNode(treeView, n, server);
            _progress.Value++;
         }
         
          //如果服务器的版本文件数量大于本地文件数量,视为有更新。 
          if (_xml.HasNewVersion ==  false && server !=  null && _xml.FilesCount < server.FilesCount)
         _xml.HasNewVersion =  true;
      }
      
       private  void CreateNode(TreeView treeView, XmlNode n, XmlLoader comparer)
      {
          //取参数n的Attributies["fullPath"].Value 
          //如:Value=".\b\b\b.txt" 多级目录 
          string fullPath = n.Attributes["fullPath"].Value;
          string[] part = fullPath.Split( new  char[] {  char.Parse(@"\") });
         TreeNode currNode =  null;
          foreach ( string p  in part)
         {
             if (p == ".")  continue; //当前目录,不处理 
             if (p.Length > 3 && p.IndexOf(".") > 0) //文件
            {
               TreeNode node =  new TreeNode(p);
               
                if (comparer ==  null)
               node.ImageIndex = 0;  //文件 
                else
               {
                  XmlNode node2 = comparer.GetFileNode(fullPath);
                  
                   if (_xml.CompareNode(node2, n))
                  {
                     node.ImageIndex = 2;
                     node.SelectedImageIndex = 2;
                     _xml.HasNewVersion =  true;
                  }
                   else
                  node.ImageIndex = 0;
               }
               
                if (currNode ==  null)
               treeView.Nodes.Add(node);  //加入根结点 
                else
               currNode.Nodes.Add(node); //加入子结点 
               
                return;
            }
             else //子目录
            {
               TreeNode tempNode = FindNode(treeView, currNode, p);  //查找当前目录 
               
                if (tempNode ==  null) //未找到结点.则创建结点
               {
                  TreeNode tmp =  new TreeNode(p);
                  tmp.ImageIndex = 1; //子目录 
                   if (currNode ==  null)
                  treeView.Nodes.Add(tmp);  //创建根目录 
                   else
                  currNode.Nodes.Add(tmp);  //在当前目录创建子目录 
                  
                  currNode = tmp;
               }
                else
               currNode = tempNode;  //保存当前目录,方便查找下一级 
            }
         }
      }
      
       //查找结点,此方法仅在CreateNode方法有效.为CreateNode方法的子方法。 
       private TreeNode FindNode(TreeView treeView, TreeNode currNode,  string text)
      {
          if (currNode ==  null) //在根目录搜索
         {
             foreach (TreeNode node  in treeView.Nodes)
             if (node.Text.ToUpper() == text.ToUpper())  return node; //找到 
         }
          else //在当前目录搜索
         {
             foreach (TreeNode node  in currNode.Nodes)
             if (node.Text.ToUpper() == text.ToUpper())  return node; //找到 
         }
          return  null//未找到 
      }
   }
}

UpgraderClient.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;

namespace VJSDN.Tech.AutoUpgraderLib
{
    /// <summary> 
    /// Tcp/ip下载器客户端 
    /// </summary> 
    public  class UpgraderClient
   {
       private OutputInvoke _writeOutput =  null;
      
       public UpgraderClient(OutputInvoke writeOutput)
      {
         _writeOutput = writeOutput;
      }
      
       private TcpClient _Client =  null;
       private TcpClient Client
      {
          get
         {
             if (_Client ==  null)
            {
               _Client =  new TcpClient();
            }
             return _Client;
         }
      }
      
       public  void CloseClient()
      {
          if (_Client !=  null && _Client.Connected) _Client.Close();
      }
      
       /// <summary> 
       /// 下载文件 
       /// </summary> 
       public  bool DownloadFile( string file,  string savePath)
      {
          try
         {
            TcpClient client =  new TcpClient();
             //client.ReceiveTimeout = 1000 * 60; 
            
             if (client ==  null || file.Trim() == "")  return  false;
            
            TryConnect(client, AppSettings.Instance.ServerIP, AppSettings.Instance.ServerPort);  //连接服务器 
             if (!client.Connected)  return  false; //连线线失败,退出 
            
             byte[] bs = Encoding.Unicode.GetBytes("GET_FILE|" + file);
            client.Client.Send(bs);  //发送请求 
            
             //开始接受数据.... 
            NetworkStream ns = client.GetStream();
            MemoryStream ms =  new System.IO.MemoryStream();
            
             byte[] resBytes =  new  byte[256];  //一次接收256字节 
             int resSize;  //当前接收到的数据长度 
             do
            {
                //开始监听,同时中断下面代码执行,直到接收到数据才会执行Read()下面的代码。 
               resSize = ns.Read(resBytes, 0, resBytes.Length);
               
                string msg = Byte2Str(resBytes);
                if (msg.Trim().ToUpper() == "FILE_NOT_FOUND")
               {
                   if (_writeOutput !=  null) _writeOutput("找不到文件:" + file);
                   break;
               }
                if (resSize == 0)  break;
               
               ms.Write(resBytes, 0, resSize);
               }  while (ns.DataAvailable);
               ns.Close();  //关闭网络数据流 
               
                if (ms.Length > 0)
               {
                  FileStream fs = File.Open(savePath, FileMode.OpenOrCreate, FileAccess.Write);
                  fs.Write(ms.ToArray(), 0, ( int)ms.Length);
                  fs.Flush();
                  fs.Close();  //关闭文件流 
                   if (_writeOutput !=  null) _writeOutput("文件已下载:" + file);
               }
               
               ms.Close();  //关闭内存流 
               client.Close(); //关闭网络套接 
                return  true;
            }
             catch
            {
                return  false;
            }
         }
         
          private  string Byte2Str( byte[] buffer)
         {
             string msg = Encoding.Unicode.GetString(buffer).Replace("\0", "");
             return msg.Trim();
         }
         
          private  void TryConnect(TcpClient client,  string hostIP,  int hostPort)
         {
             try
            {
               client.Connect(IPAddress.Parse(hostIP), hostPort);  //连接服务器 
            }
             catch
            {
                throw  new Exception("主机已关闭或网络存在问题,不能建立连线!");
            }
         }
      }
   }

UpgraderServer.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Windows.Forms;
using System.IO;

namespace VJSDN.Tech.AutoUpgraderLib
{
   
    //跨线程调用控件显示消息 
    public  delegate  void OutputInvoke( string msg);
   
    /// <summary> 
    /// tcp/ip下载器服务器 
    /// </summary> 
    public  class UpgraderServer
   {
       private TcpListener _ServerListener =  null//本地消息监听器 
       private Thread _ServerListenerThread =  null//监听器使用的线程 
       private  bool _ServerRunning =  false;
      
       private Form _owner =  null;
       private OutputInvoke _writeOutput =  null;
      
       public UpgraderServer(Form owner, OutputInvoke method)
      {
         _owner = owner;
         _writeOutput = method;
      }
      
       //启动聊天服务器程序. 参数说明 ip:本地消息服务器IP地址; port:端口 
       public  void StartListening( string ip,  int port)
      {
          if (_ServerRunning)  return;
         
          //构建监听器 
         _ServerListener =  new TcpListener(IPAddress.Parse(ip), port);
         _ServerListener.Start(255);
         _ServerRunning =  true;
         
          //启动线程 
         _ServerListenerThread =  new Thread( new ThreadStart(DoStartServerListener));
         _ServerListenerThread.IsBackground =  true;
         _ServerListenerThread.Start();
      }
      
       //关闭聊天服务器程序. 
       public  void Stop()
      {
         _ServerRunning =  false;
         _ServerListenerThread.Abort(101);
         _ServerListenerThread =  null;
         _ServerListener.Stop();
      }
      
       /// <summary> 
       ///启动服务器程序. 
       /// </summary> 
       private  void DoStartServerListener()
      {
          //监听客户连线请求 
          while (_ServerRunning)
         {
             try
            {
                if (_ServerListener ==  nullreturn//防止其它地方关闭监听器 
               Application.DoEvents();
               Socket socket = _ServerListener.AcceptSocket();  //有客户请求连接 
                if (socket ==  nullcontinue;
               
                byte[] buffer =  new Byte[socket.ReceiveBufferSize];
                int i = socket.Receive(buffer);  //接收请求数据. 
                if (i <= 0)  continue;
               
                string msg = Encoding.Unicode.GetString(buffer).Replace("\0", "");
               msg = msg.Trim();
                if (msg.ToUpper().StartsWith("GET_FILE")) //命令字符串:GET_FILE|.\a.dll
               {
                   string[] sps = msg.Split( new  char[] {  char.Parse("|") });
                   string file = sps[1];  //取出文件a.dll 
                   this.SendFile(socket, file);
               }
               socket.Close(); // 
            }
             catch (Exception ex)
            {
                if (ex  is ThreadAbortException)
               {
                   if ((ex  as ThreadAbortException).ExceptionState.ToString() == "101")
                  {
                     _ServerRunning =  false;
                     ShowLog("用户关闭服务器.");
                  }
                   else
                  ShowLog(ex.Message);
               }
                else
               {
                  ShowLog(ex.Message);
               }
            }
         }
      }
      
       private  void SendFile(Socket socket,  string file)
      {
          if (File.Exists(file))
         {
            ShowLog("获取文件[" + file + "]....");
            socket.SendFile(file);
            ShowLog("[" + file + "]已发送.");
         }
          else
         {
            socket.Send(Encoding.Unicode.GetBytes("FILE_NOT_FOUND"));  //通知客户程序 
            ShowLog("[" + file + "]不存在.");
         }
      }
      
       //在_ServerListener线程内操作主线程上的控件。 
       private  void ShowLog( string log)
      {
          //访问其它线程上的控件,需要用Invoke方法 
         _owner.Invoke(_writeOutput, log);
      }
   }
}


解决方案视图:
贴图图片
附件已打包下面的源代码:
VJSDN.Tech.AutoUpgrader.exe 自动升级程序主程序
VJSDN.Tech.AutoUpgradeServer.exe tcp/ip下载器服务器程序

VJSDN.Tech.AutoUpgraderLib.dll 内的文件已分散在3个帖内

******* 请在运行程序前先配置系统参数 *******
该帖子最后修改:2009-8-13 15:25:16
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自動更新插件。 AutoUpgrader is a component for building software updates. Delphi programmers can use this component to create their own software packages without writing a single line of code, which includes ready-made wizards that can be activated for different purposes, as well as multiple languages ​​for the application interface. It uses updates and the interesting feature is that when the end user runs the update software, the application will recognize the user’s current operating system language and display the application’s interface in the same language. This component currently translates all wizards into 13 different languages, including English, Spanish, German, French, Russian, Portuguese, Italian, Chinese and more. Of course, if you are not interested in using the program’s pre-installed wizards, you can easily design an ambient wizard with your own texts and images for the entire process. If you have installed a new version of your application in the encrypted web directory, you can do so by configuring the username and password of access files, or allow this component to be displayed to the user when the login window needs it. And users can access the app by entering the appropriate username and password. With AutoUpgrader end users of your app will always use the latest version of your products. This package consists of two components, one HTTP web / HTTP based HTTP protocol (which supports upload and cache IE and …) and another acThread, a threaded caponity for use on ActiveFirms. Delphi programmers, with this component no longer need a basic design of update programs, and can focus on the logic of their program, such as updating the program to components such as AutoUpgrader.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值