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

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

上传断点续传

断点续传主要是用在上传或下载文件,一般做法是开始上传的时候,服务器返回上次已经上传的大小,如果上传完成,则返回-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。

目录
相关文章
|
2月前
|
数据处理 C# C++
如何使用C#和C++结构体实现Socket通信
如何使用C#和C++结构体实现Socket通信
|
9月前
|
缓存 安全 网络协议
socket是并发安全的吗 2
socket是并发安全的吗
196 0
|
17天前
|
C#
C# 使用Socket对接
C# 使用Socket对接
16 1
|
5月前
|
JSON C# 图形学
【Unity 3D】利用C#、Unity和Socket实现简单的在线聊天室工具(附源码 简单易懂)
【Unity 3D】利用C#、Unity和Socket实现简单的在线聊天室工具(附源码 简单易懂)
52 0
|
5月前
|
网络协议 Unix Linux
【Unity 3D】C#中Socket及TCP三次握手与四次挥手详解(超详细 图文解释)
【Unity 3D】C#中Socket及TCP三次握手与四次挥手详解(超详细 图文解释)
53 0
|
8月前
|
网络协议 安全 API
C# Socket网络编程精华篇
C# Socket网络编程精华篇
|
9月前
|
安全 网络协议 Linux
socket是并发安全的吗 1
socket是并发安全的吗
95 0
|
12月前
|
存储 开发框架 安全
在 C# 中使用 Span<T> 和 Memory<T> 编写高性能代码
在 C# 中使用 Span 和 Memory 编写高性能代码 .NET 中支持的内存类型 .NET Core 2.1 中新增的类型 访问连续内存: Span 和 Memory Span 介绍 C# 中的 Span Span 和 Arrays Span 和 ReadOnlySpan Memory 入门 ReadOnlyMemory Span 和 Memory 的优势 连续和非连续内存缓冲区 不连续的缓冲区: ReadOnly 序列 实际场景 Benchmarking 基准测试 安装 NuGet 包 Benchmarking Span 执行基准测试 解读基准测试结果 Span 限制 结论
261 0
|
PHP
PHP实现Workerman实例 高性能PHP Socket即时通讯框架
PHP实现Workerman实例 高性能PHP Socket即时通讯框架
362 0
|
16天前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。