运行程序前先要配置系统参数,配置文件保存在程序运行目录下的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>
<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; } }
}
}
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;
}
}
}
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; //未找到
}
}
}
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("主机已关闭或网络存在问题,不能建立连线!");
}
}
}
}
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);
}
}
}
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);
}
}
}
解决方案视图:
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/upgrader_files.png)
附件已打包下面的源代码:
VJSDN.Tech.AutoUpgrader.exe 自动升级程序主程序
VJSDN.Tech.AutoUpgradeServer.exe tcp/ip下载器服务器程序
VJSDN.Tech.AutoUpgraderLib.dll 内的文件已分散在3个帖内
******* 请在运行程序前先配置系统参数 *******
版本自动更新程序及3种实现策略(二)下载器实现
程序界面及系统设置
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/settings1.png)
图1-版本升级程序服务器端设置
1. 服务器端程序发布URL地址,该参数用于Web下载器连接的url地址。
2. 服务器端程序发布目录,用于tcp/ip下载器下载的目录。
3. 服务器端程序共享目录,用于Lan下载器下载的目录.
以前3个参数跟据选择的下载器类型做相应设置。
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/settings2.png)
图2- 本机配置
本地程序发布目录:用于任一下载器下载文件后存放文件的目录。
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/settings3.png)
图3-下载器设置(更新参数设置,未改名)
选择三种下载器中任何一种作为当前下载器。
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/tcpipserver.png)
图4-Tcp/Ip下载器服务器程序.
当您选择Tcp/Ip下载器升级程序,请先运行服务器端程序。
![贴图图片](http://www.vjsdn.com/bbs/UserUpload/upgrader_main.png)
图5-版本自动升级程序主界面