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

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

2015-02-02 14:08 901 查看

基于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 = 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网络通信的自动升级程序源码分析-客户端接收文件

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