Question

First, a bit of background -- I am writing a basic FTP server for a personal project. I'm currently working on retrieving files. My current implementation looks like this:

HANDLE hFile = CreateFile("file.tar.gz", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
TransmitFile(sd, hFile, fileSize, 65536, NULL, NULL, TF_USE_KERNEL_APC | TF_WRITE_BEHIND); 
CloseHandle(hFile);

It works, but the performance is questionable. At first, the transfer starts out at about 10 MB/s, but slowly decreases to about 3 MB/s. Using FileZilla Server and IIS FTP, it maintains consistent >30 MB/s transfer speeds. Therefore, I know it's not working to its full capacity. I've tried tinkering with the buffer size but it's not improved the performance. If anyone has any suggestions for a more efficient way to transfer the file, please let me know. The API documentation seems to suggest that TransmitFile was optimized for my application, which is why I chose to use it.
[Please excuse my lack of Windows API knowledge.]

Also, all of the sockets are opened on localhost.

Was it helpful?

Solution

Have you increased the socket's TCP buffer size (and potentially the TCP window size) by setting the the SO_SNDBUF and SO_RCVBUF socket options before you start transmitting? (do it after bind and before connecting)?

From the sound of the problem, faster start which then slows down, I'd guess at it being a TCP flow control issue (probably due to the TCP window being smaller than you'd like). It would be useful to look at the data flow using Wireshark (ideally before and after the change that I suggest above).

See:

OTHER TIPS

It seems MSDN isn't much of a help here, except that it confirms TransmitFile should be the right function to use here. Did you already try this?

hFile

A handle to the open file that the TransmitFile function transmits. Since the operating system reads the file data sequentially, you can improve caching performance by opening the handle with FILE_FLAG_SEQUENTIAL_SCAN.

EDIT: The next step I'd recommend would be to check how FileZilla does it (it's open source, isn't it?). Perhaps using Windows API is just not the perfect way to do this, although TransmitFile is stated as a performant function.

I tried adding TransmitFile to my code, but performance was terrible. It would just sit there for twenty seconds before starting the download.

I've read that it also seems to be asynchronous in some manner, although that's not clearly documented anywhere. Additionally, it sounds like it can cause your application to crash if you do certain operations at the wrong time: social.msdn.microsoft.com

Poor documentation and bad performance == don't use, in my book. It's two lines of C# to load a file into a byte[] and write it to the output...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top