版本自动更新程序及3种实现策略程序下载(附源码)
运行程序前先要配置系统参数,配置文件保存在程序运行目录下的upgrader.dat文件。参考上面的所介绍的系统设置界面。跟据选择的下载器类型作相应配置。 如出现以下提示,说明您还没有配置程序目录下无upgrader.dat文件. 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 == null) return 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 == null) return 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 == null) throw 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 == null) throw 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 == null) return; //防止其它地方关闭监听器 Application.DoEvents(); Socket socket = _ServerListener.AcceptSocket(); //有客户请求连接 if (socket == null) continue; 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
|