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。
C#高性能大容量SOCKET并发(九):断点续传的更多相关文章
- C#高性能大容量SOCKET并发(转)
C#高性能大容量SOCKET并发(零):代码结构说明 C#高性能大容量SOCKET并发(一):IOCP完成端口例子介绍 C#高性能大容量SOCKET并发(二):SocketAsyncEventArgs ...
- C#高性能大容量SOCKET并发(十一):编写上传客户端
原文:C#高性能大容量SOCKET并发(十一):编写上传客户端 客户端封装整体框架 客户端编程基于阻塞同步模式,只有数据正常发送或接收才返回,如果发生错误则抛出异常,基于TcpClient进行封装,主 ...
- C#高性能大容量SOCKET并发(零):代码结构说明
原文:C#高性能大容量SOCKET并发(零):代码结构说明 C#版完成端口具有以下特点: 连接在线管理(提供在线连接维护,连接会话管理,数据接收,连接断开等相关事件跟踪): 发送数据智能合并(组件会根 ...
- C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型
原文:C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型 线程模型 SocketAsyncEventArgs编程模式不支持设置同时工作线程个数,使用的NET的IO ...
- C#高性能大容量SOCKET并发(七):协议字符集
原文:C#高性能大容量SOCKET并发(七):协议字符集 UTF-8 UTF-8是UNICODE的一种变长字符编码又称万国码,由Ken Thompson于1992年创建.现在已经标准化为RFC 362 ...
- C#高性能大容量SOCKET并发(六):超时Socket断开(守护线程)和心跳包
原文:C#高性能大容量SOCKET并发(六):超时Socket断开(守护线程)和心跳包 守护线程 在服务端版Socket编程需要处理长时间没有发送数据的Socket,需要在超时多长时间后断开连接,我们 ...
- C#高性能大容量SOCKET并发(五):粘包、分包、解包
原文:C#高性能大容量SOCKET并发(五):粘包.分包.解包 粘包 使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一 ...
- C#高性能大容量SOCKET并发(三):接收、发送
原文:C#高性能大容量SOCKET并发(三):接收.发送 异步数据接收有可能收到的数据不是一个完整包,或者接收到的数据超过一个包的大小,因此我们需要把接收的数据进行缓存.异步发送我们也需要把每个发送的 ...
- C#高性能大容量SOCKET并发(四):缓存设计
原文:C#高性能大容量SOCKET并发(四):缓存设计 在编写服务端大并发的应用程序,需要非常注意缓存设计,缓存的设计是一个折衷的结果,需要通过并发测试反复验证.有很多服务程序是在启动时申请足够的内存 ...
随机推荐
- 使用原生JS+CSS或HTML5实现简单的进度条和滑动条效果(精问)
使用原生JS+CSS或HTML5实现简单的进度条和滑动条效果(精问) 一.总结 一句话总结:进度条动画效果用animation,自动效果用setIntelval 二.使用原生JS+CSS或HTML5实 ...
- 浅谈 Redis 与 MySQL 的耦合性以及利用管道完成 MySQL 到 Redis 的高效迁移
http://blog.csdn.net/dba_waterbin/article/details/8996872 ㈠ Redis 与 MySQL 的耦合性 在业务架构早期.我们 ...
- 虚拟机的ip网络设置的选择
首先看一下vm的这几个设置 通过截图可以基本看到几个网络设置的区别,具体体现在虚拟机装好以后,网络设置会多出两个适配器,不同模式会分配不同区段的ip,需要固定时主要区段要求 所以总结一下 1.桥连,适 ...
- eclipse 编写scala代码时提示computing additional info
window->proference,把方框中那两个选项去掉不选,保存即可(或者只选择scala completions(java sources)),(只不过这么做之后就没有代码提示了)遇到这 ...
- 学习鸟哥的Linux私房菜笔记(5)——目录
一.目录 目录在文件类型上用d来表示,用 / 分割目录层 Linux操作系统 都有且仅有一个起始目录,我们用一个单独的 /来表示,称其为根目录. 对每一个Shell和操作环境,都有一个当前的工作目录. ...
- Swift异常处理:throw和rethrow
Swift异常处理体现了函数式语言的特性.因此我们能够传一个会抛出异常的函数闭包(高阶函数)作为參数传到还有一个函数中(父函数),父函数能够在子函数抛出异常时直接向上抛出异常,这时用rethrowke ...
- spark 基于key排序的wordcount
java /** * 根据单词次数排序的wordcount * @author Tele * */ public class SortWordCount { private static SparkC ...
- 构建工具Gradle
1.Summary 从Android团队开始宣布放弃Eclipse转投Android Studio时,构建工具Gradle进入了Android开发者的视野.而随着热修复.插件化.编译时注解的流行, ...
- FileReader的编码问题
有一个UTF-8编码的文本文件,用FileReader读取到一个字符串,然后转换字符集:str=new String(str.getBytes(),"UTF-8");结果大部分中文 ...
- PAT 1061 - 1064 题解
这四道题来自 13 年 08 月 30 的 PAT 测试. 代码量不大,思路也比较直接.不过第一题的处理逻辑不太清晰,需要好好把握.稍有不慎就掉进坑里了(很多人被这道 20'的题坑了一个多小时心慌意乱 ...