您的位置:首页 > 理论基础 > 计算机网络

基于TCP网络通信的自动升级程序源码分析-客户端接收文件

2015-03-03 00:00 886 查看
升级程序客户端接收文件

/// <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 = 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 == null ^ file == null) throw new Exception("Either both are null or both are set. Data is " + (data == 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 = new FileStream(TempFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, 8 * 1024, FileOptions.DeleteOnClose);
data = 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 = 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网络通信的自动升级程序源码分析-客户端接收文件

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐