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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值