Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Okay I have found what seems to be ideal for me. I don't know if it's perfect, but it's pretty darn good for my needs.</p> <p>On the <code>Server</code> side, we have this code that does the work of transferring the file. The <code>chunkedFile</code> class obviously does the chunking, but this is the code that sends the information to the <code>Client</code>.</p> <pre><code> public FileMessage ReceiveFile() { byte[] buffer = chunkedFile.NextChunk(); FileMessage message = new FileMessage(); message.FileMetaData = new FileMetaData(chunkedFile.MoreChunks, buffer.LongLength, chunkedFile.CurrentPosition); message.ChunkData = new MemoryStream(buffer); TotalBytesTransferred = chunkedFile.CurrentPosition; UpdateTotalBytesTransferred(message); if (!chunkedFile.MoreChunks) { OnTransferComplete(this, EventArgs.Empty); Timer timer = new Timer(20000f); timer.Elapsed += (sender, e) =&gt; { StopSession(); timer.Stop(); }; timer.Start(); } return message; } </code></pre> <p>The client basically calls this code, and the server proceeds to get a new chunk, put it in a stream, update the <code>TotalBytesTransferred</code> based on the position of the <code>chunkedFile</code>(which keeps track of the underlying file system file that is used to draw the data from). I'll show the method <code>UpdateTotalBytesTransferred(message)</code> in a moment, as that is where all the code for the server and client reside to achieve the more granular polling of the <code>TotalBytesTransferred</code>.</p> <p>Next up is the client side work.</p> <pre><code> hostChannel = channelFactory.CreateChannel(); ((IContextChannel)hostChannel).OperationTimeout = new TimeSpan(3, 0, 0); bool moreChunks = true; using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(fileWritePath))) { writer.BaseStream.SetLength(0); while (moreChunks) { FileMessage message = hostChannel.ReceiveFile(); moreChunks = message.FileMetaData.MoreChunks; UpdateTotalBytesTransferred(message); writer.BaseStream.Position = filePosition; message.ChunkData.CopyTo(writer.BaseStream); TotalBytesTransferred = message.FileMetaData.FilePosition; filePosition += message.FileMetaData.ChunkLength; } OnTransferComplete(this, EventArgs.Empty); } </code></pre> <p>This code is very simple. It calls the host to get the file stream, and also utilizes the <code>UpdateTotalBytesTransferred(message)</code> method. It does a little bit of work to remember the position of the underlying file that is being written, and copies the stream to that file while also updating the <code>TotalBytesTransferred</code> after finishing.</p> <p>The way I achieved the granularity I was looking for was with the <code>UpdateTotalBytesTransferred</code> method as follows. It works exactly the same for both the Server and the Client.</p> <pre><code>private void UpdateTotalBytesTransferred(FileMessage message) { long previousStreamPosition = 0; long totalBytesTransferredShouldBe = TotalBytesTransferred + message.FileMetaData.ChunkLength; Timer timer = new Timer(500f); timer.Elapsed += (sender, e) =&gt; { if (TotalBytesTransferred + (message.ChunkData.Position - previousStreamPosition) &lt; totalBytesTransferredShouldBe) { TotalBytesTransferred += message.ChunkData.Position - previousStreamPosition; previousStreamPosition = message.ChunkData.Position; } else { timer.Stop(); timer.Dispose(); } }; timer.Start(); } </code></pre> <p>What this does is take in the FileMessage which is basically just a stream and some information about the file itself. It has a variable <code>previousStreamPosition</code> to remember the last position it was when it was polling the underlying stream. It also does a simple calculation with <code>totalBytesTransferredShouldBe</code> based on how many bytes are already transferred plus the total length of the stream.</p> <p>Finally, a timer is created and executed, which upon every tick checks to see if it needs to be incrementing the <code>TotalBytesTransferred</code>. If it's not supposed to update it anymore(reached the end of the stream basically), it stops and disposes of the timer.</p> <p>This all allows me to get very small reads of how many bytes have been transferred, which lets me better calculate the total progress in a more fluid way, as more accurately measure the file transfer speeds achieved.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload