C#高性能大容量SOCKET并发(九):断点续传

来源:互联网 发布:欧弟 天天向上 知乎 编辑:程序博客网 时间:2024/05/22 00:07

上传断点续传

断点续传主要是用在上传或下载文件,一般做法是开始上传的时候,服务器返回上次已经上传的大小,如果上传完成,则返回-1;下载开始的时候,由客户端上报本地已经下载大小,服务器根据位置信息下发数据,因此上传下载协议都需要带Size大小,例如我们协议格式。

上传开始:

客户端->服务器

{

[Request]

Command=Upload

Dir=Dir                        #目录,全路径名

FileName=FileName      #文件名(不包括路径)

}

服务器->客户端

{

[Response]

Command=Upload

Code= Error Code                #错误码

Message=Message                 #如果出错,返回错误描述信息

FileSize=FileSize                 #已上传文件的大小,用于续传

}

因此在接收客户端上传请求时需要下发服务器上次接收到文件地址:

        public bool DoUpload()        {            string dirName = "";            string fileName = "";            if (m_incomingDataParser.GetValue(ProtocolKey.DirName, ref dirName) & m_incomingDataParser.GetValue(ProtocolKey.FileName, ref fileName))            {                if (dirName == "")                    dirName = Program.FileDirectory;                else                    dirName = Path.Combine(Program.FileDirectory, dirName);                fileName = Path.Combine(dirName, fileName);                Program.Logger.Info("Start upload file: " + fileName);                if (m_fileStream != null) //关闭上次传输的文件                {                    m_fileStream.Close();                    m_fileStream = null;                    m_fileName = "";                }                if (File.Exists(fileName))                {                    if (!CheckFileInUse(fileName)) //检测文件是否正在使用中                    {                        m_fileName = fileName;                        m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);                        m_fileStream.Position = m_fileStream.Length; //文件移到末尾                        m_outgoingDataAssembler.AddSuccess();                        m_outgoingDataAssembler.AddValue(ProtocolKey.FileSize, m_fileStream.Length);                    }                    else                    {                        m_outgoingDataAssembler.AddFailure(ProtocolCode.FileIsInUse, "");                        Program.Logger.Error("Start upload file error, file is in use: " + fileName);                    }                }                else                {                    m_fileName = fileName;                    m_fileStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);                    m_fileStream.Position = m_fileStream.Length; //文件移到末尾                    m_outgoingDataAssembler.AddSuccess();                    m_outgoingDataAssembler.AddValue(ProtocolKey.FileSize, m_fileStream.Length);                }            }            else                m_outgoingDataAssembler.AddFailure(ProtocolCode.ParameterError, "");            return DoSendResult();        }

下载断点续传
下载开始:

客户端->服务器

{

[Request]

Command=Download

Dir=Dir                        #目录,全路径名

FileName=FileName      #文件名(不包括路径)

FileSize=FileSize          #客户端本地文件大小,用于断点续传

PacketSize=PacketSize   #下发数据包大小,单位为KB,用于速度测试

}

服务器->客户端

{

[Response]

Command= Download

Code= Error Code                #错误码

Message=Message                 #如果出错,返回错误描述信息

}

        public bool DoDownload()        {            string dirName = "";            string fileName = "";            Int64 fileSize = 0;            int packetSize = 0;            if (m_incomingDataParser.GetValue(ProtocolKey.DirName, ref dirName) & m_incomingDataParser.GetValue(ProtocolKey.FileName, ref fileName)                & m_incomingDataParser.GetValue(ProtocolKey.FileSize, ref fileSize) & m_incomingDataParser.GetValue(ProtocolKey.PacketSize, ref packetSize))            {                if (dirName == "")                    dirName = Program.FileDirectory;                else                    dirName = Path.Combine(Program.FileDirectory, dirName);                fileName = Path.Combine(dirName, fileName);                Program.Logger.Info("Start download file: " + fileName);                if (m_fileStream != null) //关闭上次传输的文件                {                    m_fileStream.Close();                    m_fileStream = null;                    m_fileName = "";                    m_sendFile = false;                }                if (File.Exists(fileName))                {                    if (!CheckFileInUse(fileName)) //检测文件是否正在使用中                    {                        m_fileName = fileName;                        m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);                        m_fileStream.Position = fileSize; //文件移到上次下载位置                        m_outgoingDataAssembler.AddSuccess();                        m_sendFile = true;                        m_packetSize = packetSize;                    }                    else                    {                        m_outgoingDataAssembler.AddFailure(ProtocolCode.FileIsInUse, "");                        Program.Logger.Error("Start download file error, file is in use: " + fileName);                    }                }                else                {                    m_outgoingDataAssembler.AddFailure(ProtocolCode.FileNotExist, "");                }            }            else                m_outgoingDataAssembler.AddFailure(ProtocolCode.ParameterError, "");            return DoSendResult();        }

多线程并发下载

断点续传的一个应用就是并发下载,做法是客户端起多个线程并发请求同一个文件,每个线程下文件的一部分,全部下载完成后,把每个数据块合并为一个文件。这个服务端和客户端协议都不需要修改,只是需要做下载逻辑的更改。

多线程并发上传

这个需要定义通讯来支持这个逻辑,主要是服务器要提供合并多个数据文件为一个文件的协议逻辑。

DEMO下载地址:http://download.csdn.net/detail/sqldebug_fan/7467745
免责声明:此代码只是为了演示C#完成端口编程,仅用于学习和研究,切勿用于商业用途。水平有限,C#也属于初学,错误在所难免,欢迎指正和指导。邮箱地址:fansheng_hx@163.com。

1 2
原创粉丝点击