ESFramework通信框架 4.0 快速上手(13) -- 文件传送,如此简单一文的详细介绍和ESFramework通信框架 4.0 快速上手(14) -- 聊天系统Demo,增加文件传送功能(附源码)一文的Demo中,我们已经尝试了ESFramework通信框架提供的文件传送功能和断点续传特性。支持断点续传是非常有意义的,比如当我们使用了1个小时的时间上传或下载一个大文件到99%的时候,网络突然断一下,就要全部重头再来,这实在是不能忍受的。现在,我们就解释一下ESFramework通信框架中文件断点续传的实现原理。

1.文件断点续传的功能由接收方管理。

2.在每次文件接收中断的时候,会创建一个等待续传的项目对象,使用ResumedFileItem类来封装相关的信息。


    /// <summary>
    /// 有可能被续传的项目。
    /// </summary>
    public class ResumedFileItem
    {
        #region SenderID
        private string senderID;
        /// <summary>
        /// 发送者的ID。
        /// </summary>
        public string SenderID
        {
            get { return senderID; }
            set { senderID = value; }
        } 
        #endregion         #region OriginFilePath
        private string originFilePath;
        /// <summary>
        /// 发送方发送的文件的全路径。
        /// </summary>
        public string OriginFilePath
        {
            get { return originFilePath; }
            set { originFilePath = value; }
        } 
        #endregion         #region OriginFileSize
        private long originFileSize = 0;
        /// <summary>
        /// 发送方发送的文件的大小。
        /// </summary>
        public long OriginFileSize
        {
            get { return originFileSize; }
            set { originFileSize = value; }
        } 
        #endregion         #region OriginFileLastUpdateTime
        private DateTime originFileLastUpdateTime;
        /// <summary>
        /// 发送方发送的文件的最后修改日期。
        /// </summary>
        public DateTime OriginFileLastUpdateTime
        {
            get { return originFileLastUpdateTime; }
            set { originFileLastUpdateTime = value; }
        } 
        #endregion         #region LocalTempFileSavePath
        private string localTempFileSavePath;
        /// <summary>
        /// 接收的临时文件的存储路径
        /// </summary>
        public string LocalTempFileSavePath
        {
            get { return localTempFileSavePath; }
            set { localTempFileSavePath = value; }
        } 
        #endregion         #region LocalFileSavePath
        private string localFileSavePath;
        /// <summary>
        /// 接收的文件存储路径
        /// </summary>
        public string LocalFileSavePath
        {
            get { return localFileSavePath; }
            set { localFileSavePath = value; }
        }
        #endregion         #region ReceivedCount
        private long receivedCount = 0;
        /// <summary>
        /// 已经接收了多少字节数。
        /// </summary>
        public long ReceivedCount
        {
            get { return receivedCount; }
            set { receivedCount = value; }
        } 
        #endregion         #region DisrupttedTime
        private DateTime disrupttedTime = DateTime.Now;
        /// <summary>
        /// 接收中断的时间。
        /// </summary>
        public DateTime DisrupttedTime
        {
            get { return disrupttedTime; }
            set { disrupttedTime = value; }
        } 
        #endregion
    }

  为何要记录如此多的信息了?这是为了当发送方再次发送同一文件给接收方时,接收方可以依据这些信息进行匹配,是否可以找到一个续传的项目,如果匹配成功,则表示可以进行续传。

要记录的这些信息从哪里获取了?首先,是发送方在发送文件的时候,会将文件的相关信息告知接收方,如 被发送文件的全路径、被发送文件的大小、被发送的文件的最后修改日期等等;其次,当接收方接收文件时,就知道了临时文件的存储路径、正式文件的存储路径;再次,当文件传输中断的时刻,可以知道当前的文件已经被传递了多少字节。有了这些信息,断点续传才成为可能。

3.使用IResumedFileManager将所有的续传项目管理起来。


    public interface IResumedFileManager
    {
        /// <summary>
        /// 当一个续传项超过多长时间没被使用,则将其移除,同时删除对应的临时文件。单位:秒。默认值:600。
        /// </summary>
        int TTL4ResumedFileItem { get; set; }         /// <summary>
        /// 是否启用文件的断点续传功能。默认值 true。
        /// </summary>
        bool Enabled { get; set; }         IAgileLogger EsfLogger { set; }         void Initialize();         void Add(ResumedFileItem resumedFileItem);         /// <summary>
        /// 当接收一个文件之前,先看能否找到续传的匹配项(同时判断临时文件是否存在)。如果没有匹配,则返回null。
        /// </summary>
        ResumedFileItem Mapping4Receive(TransmittingFileInfo fileInfo);         // <summary>
        /// 移除续传项。
        /// </summary>
        /// <param name="resumedFileItem">要移除的续传项</param>
        /// <param name="deleteTempFile">是否同时删除临时文件</param>
        void Remove(ResumedFileItem resumedFileItem, bool deleteTempFile);        
    }

   ResumedFileManager提供了定时删除过期的续传项目的功能,比如,一个续传项目在文件中断传输以后的10分钟内都没被激活,则视其为过期项目,将会被ResumedFileManager从内存中删除。这样就避免累积很多无效的续传项目对象,而浪费内存。

ResumedFileManager的Remove方法用于从内存中移除某个续传项目,其第二个参数表示是否删除临时文件,当某个续传项目因过期而被删除时,这时必须将临时文件也删除掉,以释放硬盘空间 -- 特别是对于作为文件服务器的服务端,这点更是重要的,否则,众多永远也不会被用到的临时文件将会浪费大量的硬盘空间。如果是因为找到匹配项而从管理器中移除续传项时,则不能删除临时文件,因为接下来临时文件会被继续使用。

4.当接收方在接收一个文件之前,首先调用IResumedFileManager的Mapping4Receive方法寻找续传匹配项。当同时满足三个条件时(即OriginFilePath、OriginFileSize、OriginFileLastUpdateTime),匹配才算成功。

if (item.OriginFilePath == fileInfo.OriginFilePath && item.OriginFileSize == fileInfo.FileSize && item.OriginFileLastUpdateTime == fileInfo.OriginFileLastUpdateTime)
                    {
                        return item;
                    }

如此,可以保证续传的文件与上次传输中断的文件是同一个文件。

5.当找到匹配项时,可以询问用户是否接受续传,ESPlus通过回调IFileBusinessHandler.ReadyToAcceptFileAsyn方法得到回复。

 string ReadyToAcceptFileAsyn(string senderID, string fileName, long fileLength, string comment, string fileID, ResumedFileItem resumedFileItem);             

如果返回值为null,表示拒绝接收;如果返回的存储路径与上次的存储路径相同,则表示同意续传;如果返回新的路径,则表示要求发送方重新发送整个文件。框架根据该方法的返回值而决定是否在后台启动续传。

6.如果同意续传,则接收方会告知发送方已接收的字节数,发送方可以从文件的对应偏移处开始发送后续数据。RejectOrAcceptFileContract协议说明了这一点。


    public class RejectOrAcceptFileContract
    {
        #region FileID
        private string fileID;
        public string FileID
        {
            get { return fileID; }
            set { fileID = value; }
        } 
        #endregion         #region Agree
        private bool agree;
        public bool Agree
        {
            get { return agree; }
            set { agree = value; }
        } 
        #endregion               #region ReceivedCount4ResumeFile
        private long receivedCount4ResumeFile = 0;
        /// <summary>
        /// 如果值非0,则表示续传,指示已经传递了多少字节。
        /// </summary>
        public long ReceivedCount4ResumeFile
        {
            get { return receivedCount4ResumeFile; }
            set { receivedCount4ResumeFile = value; }
        } 
        #endregion
    }

7.如果续传开始,则接收方首先需要打开原始的临时文件,并寻址到正确的偏移处。

 this.fStream = new FileStream(this.tempFilePath, FileMode.Open);
 this.fStream.Seek(item.ReceivedCount, SeekOrigin.Begin);

8.接下来就和以前一样进行正常的文件传输了。这样的设计,可以支持同一文件的无限次断点续传,也就是说,你在传送一个巨大文件的时候,哪怕中途断网很多次,也没关系,你不需要额外地重复传递哪怕一个字节。

文件断点续传原理与实现—— ESFramework 通信框架4.0 进阶(12)的更多相关文章

  1. ESPlatform 支持的三种群集模型 —— ESFramework通信框架 4.0 进阶(09)

    对于最多几千人同时在线的通信应用,通常使用单台服务器就可以支撑.但是,当同时在线的用户数达到几万.几十万.甚至百万的时候,我们就需要很多的服务器来分担负载.但是,依据什么规则和结构来组织这些服务器,并 ...

  2. 可靠通信的保障 —— 使用ACK机制发送自定义信息——ESFramework 通信框架4.0 快速上手(12)

    使用ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoOutter接口的Send方法,我们已经可以给服务端或其它在线客户端发送自定义信息了, ...

  3. 成熟的C#网络通信框架介绍——ESFramework通信框架

    (转自:http://www.cnblogs.com/zhuweisky/archive/2010/08/12/1798211.html) ESFramework通信框架是一套性能卓越.稳定可靠.强大 ...

  4. ESFramework 通信框架安全机制的设计与实现

    在分布式通信系统中,安全无疑是非常重要的.ESFramework通信框架提供了哪些安全保障了?由于ESFramework通信框架是应用层的开发框架,那么本文我们只讨论ESFramework通信框架在应 ...

  5. C++ 对象间通信框架 V2.0 ××××××× 之(二)

    公共头文件:ss_type_def.h ================================================================================ ...

  6. C++ 对象间通信框架 V2.0 ××××××× 之(五)

    类定义: ======================================================================= // MemberFuncPointer.h: ...

  7. C++ 对象间通信框架 V2.0 ××××××× 之(四)

    类定义:CMemberFuncPointer ======================================================================= // Me ...

  8. C++ 对象间通信框架 V2.0 ××××××× 之(三)

    类定义:CSignalSlot ======================================================================= // SignalSlo ...

  9. C++ 对象间通信框架 V2.0 ××××××× 之一

    V2.0 主要是信号槽连接的索引性能做了改进,新设计了程序构架实现了多级分层索引,索引时间性能基本不受连接表的大小影响. 类定义:CSignalSlot C_MemberFuncPointer C_s ...

随机推荐

  1. cookie会话技术

    会话技术 B/S请求是无状态无记忆的,脚本与脚本之间是没有联系的,导致不能进行连续的业务逻辑 Cookie技术:将会话数据保存在浏览器端 原理:服务器向浏览器发送指令,用来管理存储在浏览器端的cook ...

  2. String与StringBuild、StringBuffer的区别

    String与StringBuild.StringBuffer的区别相信困扰了好多新入门的JAVA程序员,而这也是笔试和面试的一道常见题型,如何全面的回答该问题,变得尤为重要. 首先我们需要清楚一点, ...

  3. sulime text3

    sublime text 3 详细说明--包括快捷键 sublime 插件安装 快捷键 sunlime (需要先安装package control,ctrl+shift+p,输入insall之后安装插 ...

  4. Spring Security(18)——Jsp标签

    目录 1.1     authorize 1.2     authentication 1.3     accesscontrollist Spring Security也有对Jsp标签的支持的标签库 ...

  5. C++ static与单例模式

    单例模式是应用最多的一种设计模式,它要求系统中每个类有且只能有一个实例对象. 主要优点: 1.提供了对唯一实例的受控访问. 2.由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创 ...

  6. HDOJ_就这么个烂题总是WA先放这把

    #include<stdio.h> __int64 A[100]={0}; __int64 B[100]={0}; __int64 SUM[100]={0}; int main() {in ...

  7. 初级AD域渗透系列

      net group /domain 获得所有域用户组列表 net group “domain admins” /domain 获得域管理员列表 net group “enterprise admi ...

  8. C#中的引用传递、值传递

      先来说下C#中的数据类型.分值类型和引用类型两大类. 值类型:直接存储数据的值,保存在内存中 引用类型:存储对值的引用,实际上存储的就是一个内存的地址 C#预定义的简单类型,像int,float, ...

  9. C# 语言规范_版本5.0 (第15章 委托)

    1. 委托 **(注:此章非常重要,特别是对于图形界面相关的区别于MFC和QT等的消息机制,委托是基石.) 委托是用来处理其他语言(如 C++.Pascal 和 Modula)需用函数指针来处理的情况 ...

  10. php获取url字符串截取路径的文件名和扩展名

    <?php //获取连接里边的id $url = 'http://www.rong123.com/cjbkscbsd/x_dfsdfs/24454_1_1.html'; function get ...