upload resume
Download resumeBreakpoint resuming is mainly used to upload or download files. The general practice is that when uploading starts, the server returns the size that has been uploaded last time. If the uploading is completed, it returns -1; when the download starts, the client reports that the local Download size, the server sends data according to the location information, so the upload and download protocols need to carry the Size size, such as our protocol format.
Upload starts:
Client -> Server
{
[Request]
Command=Upload
Dir=Dir #Directory, full path name
FileName=FileName #File name (excluding path)
}
Server -> Client
{
[Response]
Command=Upload
Code= Error Code #Error code
Message=Message #If there is an error, return the error description information
FileSize=FileSize #The size of the uploaded file for continued upload
}
Therefore, when receiving the upload request from the client, it is necessary to deliver the file address that the server received last time:
- 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 ) //Close the last transferred file
- {
- m_fileStream.Close();
- m_fileStream = null;
- m_fileName = "";
- }
- if (File.Exists(fileName))
- {
- if (!CheckFileInUse(fileName)) //Check if the file is in use
- {
- m_fileName = fileName;
- m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
- m_fileStream.Position = m_fileStream.Length; //The file is moved to the end
- 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; //The file is moved to the end
- 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) //Close the last transferred file { m_fileStream.Close(); m_fileStream = null; m_fileName = ""; } if (File.Exists(fileName)) { if (!CheckFileInUse(fileName)) //Check if the file is in use { m_fileName = fileName; m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite); m_fileStream.Position = m_fileStream.Length; //The file is moved to the end 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; //The file is moved to the end m_outgoingDataAssembler.AddSuccess(); m_outgoingDataAssembler.AddValue(ProtocolKey.FileSize, m_fileStream.Length); } } else m_outgoingDataAssembler.AddFailure(ProtocolCode.ParameterError, ""); return DoSendResult (); }
Download starts:Client -> Server
{
[Request]
Command=Download
Dir=Dir #Directory, full path name
FileName=FileName #File name (excluding path)
FileSize=FileSize #Client local file size for resuming the upload
PacketSize=PacketSize #Send data packet size, in KB, for speed test
}
Server -> Client
{
[Response]
Command= Download
Code= Error Code #Error code
Message=Message #If there is an error, return the error description information
}
- publicbool 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 ) //Close the last transferred file
- {
- m_fileStream.Close();
- m_fileStream = null;
- m_fileName = "";
- m_sendFile = false;
- }
- if (File.Exists(fileName))
- {
- if (!CheckFileInUse(fileName)) //Check if the file is in use
- {
- m_fileName = fileName;
- m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
- m_fileStream.Position = fileSize; //The file is moved to the last download position
- 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) //Close the last transferred file { m_fileStream.Close(); m_fileStream = null; m_fileName = ""; m_sendFile = false; } if (File.Exists(fileName)) { if (!CheckFileInUse(fileName)) //Check if the file is in use { m_fileName = fileName; m_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite); m_fileStream.Position = fileSize; //The file is moved to the last download position 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 (); }
Multi-threaded concurrent download
One application of resumable upload is concurrent download. The method is that the client starts multiple threads and requests the same file concurrently. After all the downloads are completed, each data block is merged into one file. Neither the server nor the client protocol needs to be modified, only the download logic needs to be changed.
Multi-threaded concurrent upload
This needs to define communication to support this logic, mainly because the server needs to provide protocol logic for merging multiple data files into one file.
DEMO download address: http://download.csdn.net/detail/sqldebug_fan/7467745
Disclaimer: This code is only to demonstrate C# complete port programming, only for learning and research, not for commercial purposes. The level is limited, and C# is also a beginner. Errors are inevitable. Corrections and guidance are welcome. Email address: [email protected].