0 votes
by (200 points)
edited

Is there some property or method to measure and display the kilobytes per second of a file transfer for both Ftp and Sftp?

Thanks in advance, Richard

Applies to: Rebex FTP/SSL, Rebex SFTP

3 Answers

+1 vote
by (148k points)
edited

There is no such property yet (update - it was added in build 3723), but calculating he file transfer speed is quite easy - please download this modified GetPut sample (C#) and give it a try - it now shows how to use a TransferProgress event handler to calculate the current transfer rate. It should be simple enough to follow and use in other applications. The code is for Rebex FTP or FTP/SSL, but simply changing the event args name will make it work with Rebex SFTP as well. If you prefer VB.NET, please let us know.

Sample code for Rebex FTP or FTP/SSL until 3.0.3588.0:

    // set this to 0 before each transfer
    private static long _bytesPerSecond;
    // set this to Environment.TickCount before each transfer
    private static int _eventTime;

private static void SpeedMeasuringTransferProgress(object sender, FtpTransferProgressEventArgs e)
    {
        // wait for the next event if this is a final or first event
        if (e.State == FtpTransferState.None || e.BytesSinceLastEvent == 0)
            return;

// calculate time since the last event and update the event time
        int time = Environment.TickCount;
        int timeSinceLastEvent;
        unchecked
        {
            timeSinceLastEvent = time - _eventTime;
        }
        _eventTime = time;
        if (timeSinceLastEvent == 0)
        {
            // wait for the next event if we are currently too fast
            // (happens at the beginning while data is still being cached
            // by the local TCP/IP stack
            return;
        }

// calculate the speed of the last block
        long bytesPerSecond = e.BytesSinceLastEvent * 1000 / timeSinceLastEvent;

if (_bytesPerSecond == 0)
        {
            // if this is the first block, use the current speed
            _bytesPerSecond = bytesPerSecond;
        }
        else
        {
            // otherwise use a kind of a simple moving average calculation to smooth the number slightly
            _bytesPerSecond = (_bytesPerSecond * 15 + bytesPerSecond) / 16;
        }

Console.WriteLine("Transfer speed: {0}KB/s", _bytesPerSecond / 1024);
    }

Update: Sample code for Rebex FTP or FTP/SSL 3.0.3723.0 and later

    private static void SpeedMeasuringTransferProgress(object sender, FtpTransferProgressEventArgs e)
    {
        // check whether the current speed is already available
        if (e.BytesPerSecond == 0)
            return;

Console.WriteLine("Transfer speed: {0}KB/s", e.BytesPerSecond / 1024);
    }
+1 vote
by (200 points)
edited

Thanks Lukas! Using your example code I converted to VB.NET and added a small modification to give both percentage of complete plus the KB per second:

Private _bytesPerSecond As Long
Private _eventTime As Integer
Private percentComplete As String
Private lastReport As DateTime = DateTime.MinValue

Public Sub FtpTransferProgress(ByVal sender As Object, ByVal e As FtpTransferProgressEventArgs)
    Console.ForegroundColor = ConsoleColor.Green
    ' wait for the next event if this is a final or first event
    If (e.State = FtpTransferState.None OrElse e.BytesSinceLastEvent = 0) Then
        Return
    End If

    ' calculate time since the last event and update the event time
    Dim time As Integer = Environment.TickCount
    Dim timeSinceLastEvent As Integer
    timeSinceLastEvent = time - _eventTime

    _eventTime = time
    If timeSinceLastEvent = 0 Then
        ' wait for the next event if we are currently too fast
        ' (happens at the beginning while data is still being cached by the local TCP/IP stack)
        Return
    End If

    ' calculate the speed of the last block
    Dim bytesPerSecond As Long = e.BytesSinceLastEvent * 1000 / timeSinceLastEvent

    If _bytesPerSecond = 0 Then
        ' if this is the first block, use the current speed
        _bytesPerSecond = bytesPerSecond
    Else
        ' otherwise use a kind of a simple moving average calculation to smooth the number slightly
        _bytesPerSecond = (_bytesPerSecond * 15 + bytesPerSecond) / 16
    End If

    If (DateTime.Now.Subtract(lastReport).TotalSeconds) > 1 Then
        percentComplete = String.Format("Percent complete: {0:00.0}% - ", e.BytesTransferred * 100 / _totalLength)
        lastReport = DateTime.Now
    End If

    Dim kbPerSecond As String = String.Format("Transfer speed: {0:00.0} KB/s", _bytesPerSecond / 1024)
    Console.Write(percentComplete + kbPerSecond + vbCr)

End Sub 'FtpTransferProgress

with these lines before starting file transfer:

               ' do this before each transfer
                _totalLength = GetFileSize(localFile)
                _bytesPerSecond = 0
                _eventTime = Environment.TickCount

                ftp.PutFile(localFile, remoteFile)

and since our upload transfer list comes from a database array I used this sub to determine the filesize of the localFile:

Private Function GetFileSize(ByVal MyFilePath As String) As Long
    Dim MyFile As New FileInfo(MyFilePath)
    Dim FileSize As Long = MyFile.Length
    Return FileSize
End Function

Anyway, it gave me what I needed thanks to your help!

by (148k points)
edited

Thanks to you as well! We have added build-in support for this to the latest release - check out propertyFtpTransferProgressEventArgs object's BytesPerSecond property. Note: We found out that the code we posted here doesn't work properly when the transfer speed is very high due to the limited precision of Environment.TickCount. The built-in BytesPerSecond property solves this.

0 votes
by (240 points)
edited

This feature should be built into all of Rebex products by default. It makes thing much easier. I vote for one.

by (148k points)
We agree - it is included in the latest build of Rebex FTP/SSL and Rebex SFTP! There is now a BytesPerSecond property in FtpTransferProgressEventArgs/SftpTransferProgressEventArgs classes.
...