好吧,我正在處理我的文件傳輸服務,並且可以使用WCF流傳輸文件。我獲得了很好的速度,並且我最終能夠獲得良好的簡歷支持,因爲我在流式傳輸之前將文件分塊成小塊。如何在執行流操作時實現更好的粒度?
但是,當涉及到消息流式傳輸和寫入時測量詳細傳輸速度時,我遇到了服務器端傳輸和客戶端接收問題。
以下是文件分塊的代碼,每次需要向服務器發送另一個塊時,服務都會調用該文件。
public byte[] NextChunk()
{
if (MoreChunks) // If there are more chunks, procede with the next chunking operation, otherwise throw an exception.
{
byte[] buffer;
using (BinaryReader reader = new BinaryReader(File.OpenRead(FilePath)))
{
reader.BaseStream.Position = currentPosition;
buffer = reader.ReadBytes((int)MaximumChunkSize);
}
currentPosition += buffer.LongLength; // Sets the stream position to be used for the next call.
return buffer;
}
else
throw new InvalidOperationException("The last chunk of the file has already been returned.");
在上文中,我基本上寫基於我使用的塊大小的緩衝液(在此情況下它是2MB,我發現具有相比更大或更小的塊大小的最佳傳輸速度)。然後,我會做一些工作來記住我離開的位置,然後返回緩衝區。
以下代碼是服務器端的工作。
public FileMessage ReceiveFile()
{
if (!transferSpeedTimer.Enabled)
transferSpeedTimer.Start();
byte[] buffer = chunkedFile.NextChunk();
FileMessage message = new FileMessage();
message.FileMetaData = new FileMetaData(chunkedFile.MoreChunks, buffer.LongLength);
message.ChunkData = new MemoryStream(buffer);
if (!chunkedFile.MoreChunks)
{
OnTransferComplete(this, EventArgs.Empty);
Timer timer = new Timer(20000f);
timer.Elapsed += (sender, e) =>
{
StopSession();
timer.Stop();
};
timer.Start();
}
//This needs to be more granular. This method is called too infrequently for a fast and accurate enough progress of the file transfer to be determined.
TotalBytesTransferred += buffer.LongLength;
return message;
}
在這種方法中,它是由客戶端在WCF電話叫,我得到了一個塊信息,創建我的消息,請與定時器一點點,一旦轉讓完成,停止我的會議和更新傳輸速度。在我返回消息之前不久,我用緩衝區的長度增加了我的TotalBytesTransferred
,緩衝區的長度用於幫助我計算傳輸速度。
問題是,這需要一段時間才能將文件流式傳輸到客戶端,因此我得到的速度是錯誤的。我試圖在這裏瞄準的是對TotalBytesTransferred
變量進行更細緻的修改,以便更好地表示在任何給定時間向客戶端發送了多少數據。
現在,對於客戶端代碼,它使用完全不同的計算傳輸速度的方法。
if (Role == FileTransferItem.FileTransferRole.Receiver)
{
hostChannel = channelFactory.CreateChannel();
((IContextChannel)hostChannel).OperationTimeout = new TimeSpan(3, 0, 0);
bool moreChunks = true;
long bytesPreviousPosition = 0;
using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(fileWritePath)))
{
writer.BaseStream.SetLength(0);
transferSpeedTimer.Elapsed += ((sender, e) =>
{
transferSpeed = writer.BaseStream.Position - bytesPreviousPosition;
bytesPreviousPosition = writer.BaseStream.Position;
});
transferSpeedTimer.Start();
while (moreChunks)
{
FileMessage message = hostChannel.ReceiveFile();
moreChunks = message.FileMetaData.MoreChunks;
writer.BaseStream.Position = filePosition;
// This is golden, but I need to extrapolate it out and do the stream copy myself so I can do calculations on a per byte basis.
message.ChunkData.CopyTo(writer.BaseStream);
filePosition += message.FileMetaData.ChunkLength;
// TODO This needs to be more granular
TotalBytesTransferred += message.FileMetaData.ChunkLength;
}
OnTransferComplete(this, EventArgs.Empty);
}
}
else
{
transferSpeedTimer.Elapsed += ((sender, e) =>
{
totalElapsedSeconds += (int)transferSpeedTimer.Interval;
transferSpeed = TotalBytesTransferred/totalElapsedSeconds;
});
transferSpeedTimer.Start();
host.Open();
}
在這裏,我TotalBytesTransferred
也是基於的塊進來的長度。我知道我能得到一個更精確的計算,如果我做的流寫我自己,而不是使用CopyTo
的流,但我我不完全確定如何最好地解決這個問題。
有人可以幫我嗎?在這個班級之外,我有另一個班級輪詢TransferSpeed
的財產,因爲它在內部更新。
我道歉如果我張貼了太多的代碼,但我不知道要發佈什麼,什麼不是。
編輯:我意識到,至少在服務器端的實現中,我可以通過讀取流的返回消息值的位置來更詳細地讀取已傳輸多少字節的方式。但是,我不知道這樣做的方式,以確保我的數量絕對完整。我想過可能會使用定時器並在流傳輸時輪詢位置,但接下來可能會進行調用,並且很快就會失去同步。
如何從返回的流中輪詢數據並立即知道流何時完成,以便我可以快速將剩餘流的剩餘部分累加到字節數中?