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