C#.Net版本自动更新程序及3种策略实现
C/S程序是基于客户端和服务器的,在客户机编译新版本后将文件发布在更新服务器上,然后建立一个XML文件,该文件列举最新程序文件的版本号及最后修改日期。如程序文件较多的话可以通过工具自动生成XML文件。当某客户机运行程序后会自动下载这个XML文件,通过与本地机器上的版本号匹配,如本机上的版本号比服务器上的要旧,通知客户机运行更新程序。如用户更新了版本,将最新版本号写入配置文件,这样方便下一次匹配。
通过可行性分析可以使用下面3种方案下载
1.
局域网共享文件夹下载
2. Tcp/ip远程下载
3.
通过Web方式下载
1.局域网共享文件夹下载
方式1适合局域网络,功能简单,通过File.Copy()方式从服务器直接复制文件。如建立企业级的VPN网络,也可作为局域网络直接复制。共享文件夹下载实现非常简单,我们只需要在服务器上共享一个文件夹并设定访问权限,然后将最新版本存放在这个目录,升级程序直接从这个目录Copy文件即可。
2.Tcp/ip远程下载
方式2是通过基于tcp/ip
的Socket组件编程来实现,这个机制必须要建立服务器用于监听客户的升级请求。简单设计思路是在服务器端启动TcpListener监听客户端的Socket连接,当Client发送连接请求,TcpListener捕获当前请求的Socket,并取到请求命令数据(字符串),然后由命令处理程序分析该字符串,如果字符串头部包含GET_FILE标识则为下载文件。举例说明:客户机向服务器程序发送请求命令:"GET_FILE|D:\PUBLISH\TEST.DLL"。首先TcpListener捕获当前Socket.并接收到命令数据"GET_FILE|D:\PUBLISH\TEST.DLL",通过分析程序发现"GET_FILE"是特殊命令,表示下载文件请求。然后通过socket.SendFile(file="D:\PUBLISH\TEST.DLL")将文件传送给当前Socket。客户端由NetworkStream.Read()方法接收由服务器传来的文件。
3.通过Web方式下载。
方式3是通过.NetFramework提供的WebClient组件下载文件。只需指定DownloadData()方法中参数address(url)。
下面讲解版本更新程序系统框架图:
主窗体<->下载控制器<->XmlLoader关系图

图解:
frmUpgrader窗体定义一个下载控制器及2个TreeView组件。
当点[检查更新]按钮,控制器调用当前下载器的DownloadServerXml()方法从服务器下载XmlServerFiles.xml文件。
下载后将文件交给XmlLoader分析,分析器创建XmlDocument实例。最后将XML分析器作为FileView构造器参数创建FileView实例。
FileView两个重要方法:
LoadTreeViewClient()方法创建客户端文件清单的TreeView。
LoadTreeViewServer()方法创建服务器端文件清单的TreeView。
TreeView的数据来源是两个Xml文件。
DownloadController
下载控制器,它负责建立下载策略实例及控制当前的下载器。
XmlLoader分析器主要功能是分析服务器端及本地的XML文件(XmlServerFiles.xml和XmlClientFiles.xml)。XmlLoader类图列举了所有方法,从图中可以看出,XmlLoader控制XmlDocument对象。通过XmlDocument.SelectSingleNode方法查找某个指定的文件,然后获取文件最后修改日期文件名等信息用于匹配。
IDownloader接口定义了下载器的主要方法,下面会详细讲解3个下载器的实现策略。
FileInfo是文件的实体类,结构相当简单,只包含文件名,物理路径及最后修改时间。
三种下载器实现:

UML图说明:
frmUpgrader:
主窗体
DownloadController:下载控制器,如上图所示,它负责控制实现IDownloader接口的实例。
IDownloader:
下载器接口,下载器需要实现这个接口。
LAN_Downloader:
局域网复制文件下载器。
WebClient_Downloader:
广域网下载器,通过WebClient组件下载文件。
TcpIp_Downloader:
Tcp/ip下载器。需要运行Tcp/ip服务器提供下载服务。
主窗体有[检查更新]及[开始更新]两个按钮。分别调用下载控制器的CheckUpdate()及Download()方法。
Tcp/IP下载器图解:

Tcp/IP下载器需要有服务器支持,使用tcp/ip传送文件简单设计思路是:在服务器端启动TcpListener监听客户端的Socket连接,当Client发送连接请求,TcpListener捕获当前请求的Socket,并取到请求命令数据(字符串),然后由命令处理程序分析该字符串,如果字符串头部包含GET_FILE标识则为下载文件。
UpgraderServer
是tcp/ip服务器的核心类。他控制TcpListener对象,TcpListener负责监听客户端的Socket连接。
当有下载文件请求时就调用SendFile()方法将文件传送给当前连接的Socket.
Stop()方法用来关闭服务器.
SendFile()方法用来发送文件
StartListening()方法用户启动监听程序。
TcpListener是监听程序,它负责监听客户端的Socket连接。如有连接请求触发AccecptSocket事件。该事件返回当前请求的Socket对象。
UpgraderClient是tcp/ip客户端的核心类。他控制TcpClient对象,
TcpClient对象负责监听来自服务器的请求。
DownloadFile()方法详解:
要明白客户端是如何接收文件,先要明白NetworkStream对象.
NetworkStream是提供用于网络访问的基础数据流。客户机监听来自服务器的数据是通过NetworkStream.Read()方法实现的,当程序执行到ns.Read()方法时就开始监听,请看代码。
byte[] resBytes
= new byte[256];
int resSize;
do
{
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();
请注意while
(ns.DataAvailable)这段代码,当接受到来自服务器的数据时DataAvailable=True,然后通过NetworkStream.Read方法每次读取256字节,直到读取完所有数据时DataAvailable=false。这时监听工作完成,跳出while循环。最后调用FileStream对象保存文件。
TcpIp_Downloader
Tcp/IP下载器方法:
Download():下载XmlServerFiles.xml定义的所有文件。
DownloadFile(FileInfo
file):下载单个文件。
DownloadServerXml():下载服务器上的文件清单。
Init()
//初始化下载器。
IDownloader下载器接口定义
public interface IDownloader
{
void Init();
void Download();
FileInfo
DownloadFile(FileInfo file);
XmlLoader
XmlServer { get;} //服务器上的Xml文件
XmlLoader
XmlLocal { get;}//客户机上的Xml文件
int DownloadsCount { get;} //下载成功的文件总数
int DownloadFaliedCount { get;}//下载失败的文件总数
void DownloadServerXml();
void SetProgressBar(ToolStripProgressBar
progress);
void SetTrace(ListBox
logList);
}
下载器类型
public enum DownloadType
{
Intranet
= 1,
TcpIp = 2,
WebDownload =
3
}
下载控制器,该控件器可以创建3种不同的下载器。
public class DownloadController
{
private IDownloader _downloader
= null;
public IDownloader CurrentDownloader
{ get { return _downloader;
} }
private TreeView
_tvServerFiles;
private TreeView
_tvLocalFiles;
private ListBox
_log;
private ToolStripProgressBar _progress
= null;
public DownloadController(IDownloader
downloader)
{
_downloader
=
downloader;
}
public static DownloadController
Create(DownloadType
type)
{
if (DownloadType.Intranet ==
type)
return new DownloadController(new LAN_Downloader());
if (DownloadType.TcpIp ==
type)
return new DownloadController(new TcpIp_Downloader());
if (DownloadType.WebDownload ==
type)
return new DownloadController(new WebClient_Downloader());
return null;
}
public void Download()
{
_log.Items.Add("开始下载....");
_downloader.SetProgressBar(_progress);
_downloader.Init();
_downloader.SetTrace(_log);
_downloader.Download();
_log.Items.Add("下载完成....");
_log.Items.Add("刷新文件列表....");
new FileView(_downloader.XmlLocal,
_progress).LoadTreeViewClient(_tvLocalFiles, null);
_log.Items.Add("完成.");
}
public void CheckUpdate()
{
_log.Items.Add("开始检查服务器上有用更新....");
_downloader.SetProgressBar(_progress);
_downloader.Init();
_downloader.SetTrace(_log);
new FileView(_downloader.XmlServer,
_progress).LoadTreeViewServer(_tvServerFiles);
new FileView(_downloader.XmlLocal,
_progress).LoadTreeViewClient(_tvLocalFiles,
_downloader.XmlServer);
if (_downloader.XmlLocal.HasNewVersion)
_log.Items.Add("服务器上有最新版本,请更新.");
else
_log.Items.Add("检查完成,没有发现新版本.");
}
public void BindControls(TreeView tvServerFiles,
TreeView tvLocalFiles, ListBox log, ToolStripProgressBar
progress)
{
_progress
= progress;
_tvLocalFiles =
tvLocalFiles;
_tvServerFiles =
tvServerFiles;
_log =
log;
}
}
文件对象定义
public class FileInfo
{
private string _name =
"";
private string _FullPath =
"";
private DateTime _ModifyTime =
DateTime.MinValue;
public FileInfo()
{ }
public FileInfo(string fileName, string fullPath,
DateTime
lastEditDate)
{
this.Name =
fileName;
this.FullPath =
fullPath;
this.ModifyTime =
lastEditDate;
}
public string Name { get { return _name; } set {
_name = value; } }
public string FullPath { get { return _FullPath; } set {
_FullPath = value; } }
public DateTime ModifyTime { get { return _ModifyTime; } set {
_ModifyTime = value; } }
public override string ToString()
{
return this.Name;
}
}
XML文件解释器,分析服务器/客户端的xml文件
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Collections;
using System.Windows.Forms;
namespace CSFramework.Tech.AutoUpgraderLib
{
public class XmlLoader
{
private XmlDocument
_xml;
public XmlDocument XML { get { return _xml; }
}
private string _xmlFilePath;
public XmlLoader(string xmlFile)
{
_xml
= new XmlDocument();
_xmlFilePath
= xmlFile;
if (System.IO.File.Exists(xmlFile))
_xml.Load(xmlFile);
}
private bool _HasNewVersion = false;
public bool HasNewVersion { get { return _HasNewVersion; } set {
_HasNewVersion = value; }
}
public static XmlLoader CreateEmpty(string xmlFilePath)
{
string xml
=
"<?xml
version=\"1.0\" encoding=\"utf-8\" ?> \r\n"
+
"<Upgrader>
\r\n"
+
"<description>本机最近更新清单</description>
\r\n"
+
"<Application>
\r\n"
+
"<LastUpdateTime
value=\"\" /> \r\n"
+
"<Version
value=\"\" /> \r\n"
+
"</Application>
\r\n"
+
"<Files>
\r\n"
+
"</Files>
\r\n"
+
"</Upgrader>
\r\n";
if (File.Exists(xmlFilePath))
File.Delete(xmlFilePath);
string dir =
Path.GetDirectoryName(xmlFilePath);
if (!Directory.Exists(dir)) throw new Exception("不存在目录:" +
dir);
StreamWriter
sw =
File.CreateText(xmlFilePath);
sw.Write(xml);
sw.Flush();
sw.Close();
return new XmlLoader(xmlFilePath);
}
public void SetLastUpdateInfo(string version,
DateTime
lastUpdateTime)
{
XmlNode
nodeVersion =
_xml.SelectSingleNode("Upgrader/Application/Version");
XmlNode
nodeTime =
_xml.SelectSingleNode("Upgrader/Application/LastUpdateTime");
nodeVersion.Attributes["value"].Value
=
version;
nodeTime.Attributes["value"].Value
=
lastUpdateTime.ToString();
}
public string GetVersion()
{
XmlNode
ver =
_xml.SelectSingleNode("Upgrader/Application/Version");
if (ver != null)
return ver.Attributes["value"].Value;
else
return "";
}
public bool CompareFile(FileInfo
file)
{
if (file == null) return true;
XmlNode
node = this.GetFileNode(file.FullPath);
if (node == null) return true;
DateTime
date;
if (DateTime.TryParse(node.Attributes["lastModify"].Value, out date))
{
return file.ModifyTime.CompareTo(date)
>
0;
}
return false;
}
public bool CompareNode(XmlNode node1, XmlNode
node2)
{
if (node1 == null ||
node2 == null) return false;
DateTime
date1 =
Common.StrToDate(node1.Attributes["lastModify"].Value);
DateTime
date2 =
Common.StrToDate(node2.Attributes["lastModify"].Value);
return date1.CompareTo(date2) >
0;
}
public XmlNode GetFileNode(string fullPath)
{
string xPath =
@"Upgrader/Files/File[@fullPath=‘‘" + fullPath +
"‘‘]";
XmlNode
node =
_xml.SelectSingleNode(xPath);
return node;
}
public FileInfo GetFileInfo(string fullPath)
{
XmlNode
node = this.GetFileNode(fullPath);
if (node != null)
{
FileInfo
fi = new FileInfo();
fi.FullPath
=
node.Attributes["fullPath"].Value;
fi.ModifyTime
=
Common.StrToDate(node.Attributes["lastModify"].Value);
fi.Name
=
node.Attributes["fileName"].Value;
return fi;
}
return null;
}
public void AddOrUpdateHistory(FileInfo
serverFile, FileInfo
clientFile)
{
XmlNode
node =
GetFileNode(serverFile.FullPath);
if (node == null)
{
XmlNode
fileRoot =
_xml.SelectSingleNode("Upgrader/Files");
node
= _xml.CreateNode(XmlNodeType.Element, "File",
"");
fileRoot.AppendChild(node);
}
node.RemoveAll();
node.Attributes.Append(CreateAttribute("fileName",
clientFile.Name));
node.Attributes.Append(CreateAttribute("fullPath",
serverFile.FullPath));
node.Attributes.Append(CreateAttribute("lastModify",
serverFile.ModifyTime.ToString()));
}
private XmlAttribute CreateAttribute(string name, string value)
{
XmlAttribute
attr =
_xml.CreateAttribute(name);
attr.Value
= value;
return attr;
}
public void Save()
{
_xml.Save(_xmlFilePath);
}
public int FilesCount
{
get
{
XmlNode
node =
_xml.SelectSingleNode("Upgrader/Files");
return node.ChildNodes.Count;
}
}
public IList
GetFiles()
{
IList
files = new ArrayList();
XmlNode
node =
_xml.SelectSingleNode("Upgrader/Files");
foreach (XmlNode n in node.ChildNodes)
{
FileInfo
sf = new FileInfo();
sf.FullPath
=
n.Attributes["fullPath"].Value;
sf.ModifyTime
=
Common.StrToDate(n.Attributes["lastModify"].Value);
sf.Name
=
n.Attributes["fileName"].Value;
files.Add(sf);
}
return files;
}
}
}
refer to
: http://www.csframework.com/archive/1/arc-1-20110626-1655.htm
C#.Net版本自动更新程序及3种策略实现,布布扣,bubuko.com
C#.Net版本自动更新程序及3种策略实现
原文:http://www.cnblogs.com/kinpauln/p/3656022.html