首页 > 代码库 > 基于TCP网络通信的自动升级程序源码分析-客户端接收文件
基于TCP网络通信的自动升级程序源码分析-客户端接收文件
升级程序客户端接收文件
/// <summary> /// 文件数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是数据 /// </summary> Dictionary<ConnectionInfo, Dictionary<long, byte[]>> incomingDataCache = new Dictionary<ConnectionInfo, Dictionary<long, byte[]>>(); /// <summary> /// 文件信息数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是文件信息数据 /// </summary> Dictionary<ConnectionInfo, Dictionary<long, SendInfo>> incomingDataInfoCache = new Dictionary<ConnectionInfo, Dictionary<long, SendInfo>>();
构造函数中注册
PartialFileData 逻辑类型 代表文件数据部分
PartialFileDataInfo 逻辑类型 代表文件数据相关信息部分
//处理文件数据 <2 > NetworkComms.AppendGlobalIncomingPacketHandler<byte[]>("PartialFileData", IncomingPartialFileData); //处理文件信息 <3> NetworkComms.AppendGlobalIncomingPacketHandler<SendInfo>("PartialFileDataInfo", IncomingPartialFileDataInfo);
具体的处理方法
/// <summary> /// 处理文件数据 /// </summary> private void IncomingPartialFileData(PacketHeader header, Connection connection, byte[] data) { try { SendInfo info = null; ReceiveFile file = null; lock (syncRoot) { //获取数据包的顺序号 long sequenceNumber = header.GetOption(PacketHeaderLongItems.PacketSequenceNumber); //如果数据信息字典包含 "连接信息" 和 "包顺序号" if (incomingDataInfoCache.ContainsKey(connection.ConnectionInfo) && incomingDataInfoCache[connection.ConnectionInfo].ContainsKey(sequenceNumber)) { //根据顺序号,获取相关SendInfo记录 info = incomingDataInfoCache[connection.ConnectionInfo][sequenceNumber]; //从信息记录字典中删除相关记录 incomingDataInfoCache[connection.ConnectionInfo].Remove(sequenceNumber); //检查相关连接上的文件是否存在,如果不存在,则添加相关文件{ReceiveFile} if (!recvManager.ContainsFileID(info.FileID)) { recvManager.AddFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes); } file = recvManager.GetFile(info.FileID); } else { //如果不包含顺序号,也不包含相关"连接信息",添加相关连接信息 if (!incomingDataCache.ContainsKey(connection.ConnectionInfo)) incomingDataCache.Add(connection.ConnectionInfo, new Dictionary<long, byte[]>()); //在数据字典中添加相关"顺序号"的信息 incomingDataCache[connection.ConnectionInfo].Add(sequenceNumber, data); } } if (info != null && file != null && !file.IsCompleted) { file.AddData(info.BytesStart, 0, data.Length, data); file = null; data = null; } else if (info == null ^ file == null) throw new Exception("Either both are null or both are set. Info is " + (info == null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed.")); } catch (Exception ex) { LogTools.LogException(ex, "IncomingPartialFileDataError"); } } /// 处理文件数据信息 private void IncomingPartialFileDataInfo(PacketHeader header, Connection connection, SendInfo info) { try { byte[] data = http://www.mamicode.com/null; ReceiveFile file = null; //以线程安全的方式执行操作 lock (syncRoot) { //从 SendInfo类中获取相应数据类的信息号 以便可以对应。 long sequenceNumber = info.PacketSequenceNumber; if (incomingDataCache.ContainsKey(connection.ConnectionInfo) && incomingDataCache[connection.ConnectionInfo].ContainsKey(sequenceNumber)) { data = incomingDataCache[connection.ConnectionInfo][sequenceNumber]; incomingDataCache[connection.ConnectionInfo].Remove(sequenceNumber); if (!recvManager.ContainsFileID(info.FileID)) { recvManager.AddFile(info.FileID, info.Filename, info.FilePath, connection.ConnectionInfo, info.TotalBytes); } file = recvManager.GetFile(info.FileID); } else { if (!incomingDataInfoCache.ContainsKey(connection.ConnectionInfo)) incomingDataInfoCache.Add(connection.ConnectionInfo, new Dictionary<long, SendInfo>()); incomingDataInfoCache[connection.ConnectionInfo].Add(sequenceNumber, info); } } if (data != null && file != null && !file.IsCompleted) { file.AddData(info.BytesStart, 0, data.Length, data); file = null; data = null; } else if (data =http://www.mamicode.com/= null ^ file == null) throw new Exception("Either both are null or both are set. Data is " + (data =http://www.mamicode.com/= null ? "null." : "set.") + " File is " + (file == null ? "null." : "set.") + " File is " + (file.IsCompleted ? "completed." : "not completed.")); } catch (Exception ex) { LogTools.LogException(ex, "IncomingPartialFileDataInfo"); } }
ReceiveFile类
public class ReceiveFile : INotifyPropertyChanged { //传输过程 public event EventHandler<FTProgressEventArgs> FileTransProgress; //传输完成 public event EventHandler<FTCompleteEventArgs> FileTransCompleted; //传输中断 public event EventHandler<FTDisruptEventArgs> FileTransDisruptted; /// <summary> /// The name of the file /// 文件名 (没有带路径) /// </summary> public string Filename { get; private set; } /// <summary> /// The connectionInfo corresponding with the source /// 连接信息 /// </summary> public ConnectionInfo SourceInfo { get; private set; } //文件ID 用于管理文件 和文件的发送 取消发送相关 private string fileID; public string FileID { get { return fileID; } set { fileID = value; } } /// <summary> /// The total size in bytes of the file /// 文件的字节大小 /// </summary> public long SizeBytes { get; private set; } /// <summary> /// The total number of bytes received so far /// 目前收到的文件的带下 /// </summary> public long ReceivedBytes { get; private set; } /// <summary> /// Getter which returns the completion of this file, between 0 and 1 ///已经完成的百分比 /// </summary> public double CompletedPercent { get { return (double)ReceivedBytes / SizeBytes; } set { throw new Exception("An attempt to modify read-only value."); } } /// <summary> /// 源信息 /// </summary> public string SourceInfoStr { get { return "[" + SourceInfo.RemoteEndPoint.ToString() + "]"; } } /// <summary> /// 是否完成 /// </summary> public bool IsCompleted { get { return ReceivedBytes == SizeBytes; } } object SyncRoot = new object(); /// <summary> /// 用来创建文件的数据流 /// </summary> Stream data; public event PropertyChangedEventHandler PropertyChanged; //临时文件流存储的位置 public string TempFilePath = ""; //文件最后的保存路径 public string SaveFilePath = ""; public ReceiveFile(string fileID, string filename, string filePath, ConnectionInfo sourceInfo, long sizeBytes) { this.fileID = fileID; this.Filename = filename; this.SourceInfo = sourceInfo; this.SizeBytes = sizeBytes; //如果临时文件已经存在,则添加.data后缀 this.TempFilePath = filePath + ".data"; while (File.Exists(this.TempFilePath)) { this.TempFilePath = this.TempFilePath + ".data"; } this.SaveFilePath = filePath; //We create a file on disk so that we can receive large files //我们在硬盘上创建一个文件,使得我们可以接收大的文件 //data = http://www.mamicode.com/new FileStream(TempFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 8 * 1024, FileOptions.DeleteOnClose); data = http://www.mamicode.com/new FileStream(this.TempFilePath, FileMode.OpenOrCreate); } /// <summary> /// 添加数据到文件中 /// </summary> public void AddData(long dataStart, int bufferStart, int bufferLength, byte[] buffer) { lock (SyncRoot) { if (!this.canceled && (this.data != null)) { try { data.Seek(dataStart, SeekOrigin.Begin); data.Write(buffer, (int)bufferStart, (int)bufferLength); ReceivedBytes += (int)(bufferLength - bufferStart); FileTransProgress.Raise(this, new FTProgressEventArgs(FileID, SizeBytes, ReceivedBytes)); if (ReceivedBytes == SizeBytes) { //data.Flush(); //SaveFileToDisk(SaveFilePath); //data.Close(); this.data.Flush(); this.data.Close(); if (File.Exists(this.SaveFilePath)) { File.Delete(this.SaveFilePath); File.Move(this.TempFilePath, this.SaveFilePath); } else { File.Move(this.TempFilePath, this.SaveFilePath); } FileTransCompleted.Raise(this, new FTCompleteEventArgs(FileID)); } } catch (Exception exception) { //触发文件传输中断事件 FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error)); } } } } private volatile bool canceled; public void Cancel(FileTransFailReason disrupttedType, bool deleteTempFile) { try { this.canceled = true; this.data.Flush(); this.data.Close(); this.data = http://www.mamicode.com/null; if (deleteTempFile) { File.Delete(this.TempFilePath); } } catch (Exception) { } //通知 Receiver取消,并且触发文件传输中断事件 FileTransDisruptted.Raise(this, new FTDisruptEventArgs(FileID, FileTransFailReason.Error)); } public void Close() { try { data.Dispose(); } catch (Exception) { } try { data.Close(); } catch (Exception) { } } }
ReceiveFileDict
public class ReceiveFileDict { private object syncLocker = new object(); Dictionary<string, ReceiveFile> receivedFiles = new Dictionary<string, ReceiveFile>(); public bool ContainsFileID(string fileID) { lock (syncLocker) { return receivedFiles.ContainsKey(fileID); } } public ReceiveFile GetFile(string fileID) { lock (syncLocker) { return receivedFiles[fileID]; } } //传输过程 public event EventHandler<FTProgressEventArgs> FileTransProgress; //传输完成 public event EventHandler<FTCompleteEventArgs> FileTransCompleted; //传输中断 public event EventHandler<FTDisruptEventArgs> FileTransDisruptted; public event EventHandler<FTCancelEventArgs> FileCancelRecv; public ReceiveFileDict() { } public void AddFile(string fileID, string filename, string filePath, ConnectionInfo sourceInfo, long sizeBytes) { ReceiveFile receivedFile = new ReceiveFile(fileID,filename,filePath,sourceInfo,sizeBytes); receivedFile.FileTransProgress += new EventHandler<FTProgressEventArgs>(receivedFile_FileTransProgress); receivedFile.FileTransCompleted += new EventHandler<FTCompleteEventArgs>(receivedFile_FileTransCompleted); receivedFile.FileTransDisruptted += new EventHandler<FTDisruptEventArgs>(receivedFile_FileTransDisruptted); receivedFiles.Add(fileID, receivedFile); } void receivedFile_FileTransDisruptted(object sender, FTDisruptEventArgs e) { lock (this.syncLocker) { if (this.receivedFiles.ContainsKey(e.FileID)) { this.receivedFiles.Remove(e.FileID); } } FileTransDisruptted.Raise(this, e); } void receivedFile_FileTransCompleted(object sender, FTCompleteEventArgs e) { lock (this.syncLocker) { if (this.receivedFiles.ContainsKey(e.FileID)) { this.receivedFiles.Remove(e.FileID); } } FileTransCompleted.Raise(this, e); } void receivedFile_FileTransProgress(object sender, FTProgressEventArgs e) { FileTransProgress.Raise(this, e); } // 请求取消文件的接收 FileRecTransViewer中会调用此方法 public void CancelRecFile(string fileID) { FileCancelRecv.Raise(this, new FTCancelEventArgs(fileID)); } }
www.networkcomms.cn
www.cnblogs.com/networkcomms
【开源下载】基于TCP网络通信的自动升级程序c#源码
[源码下载]Demo2.模拟简单登陆-效果图 基于networkcomms2.3.1
[源码下载]Demo1 客户端从服务器获取信息(基于networkcomms2.3.1)
http://shop115882994.taobao.com/
相关文章:
基于TCP网络通信的自动升级程序源码分析--生成升级文件相关的配置文件
基于TCP网络通信的自动升级程序源码分析-客户端连接服务器
基于TCP网络通信的自动升级程序源码分析-客户端请求服务器上的升级信息
基于TCP网络通信的自动升级程序源码分析-启动升级文件下载程序
基于TCP网络通信的自动升级程序源码分析-服务器发送文件
基于TCP网络通信的自动升级程序源码分析-客户端接收文件
基于TCP网络通信的自动升级程序源码分析-客户端接收文件
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。