views:

306

answers:

3

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.

A: 

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.

schnaader
Adding that flag may have helped midly -- it seemed to eventually bottom out at about 6 Mb/s.
Null
+1  A: 

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:

Len Holgate
This helped drastically. I'd never actually seen these options.Thank you!
Null
Glad to hear it.
Len Holgate
A: 

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...

Gregor S.
The docs seem pretty clear on the async nature of the call, how to force it to be sync and how to tell when it's complete: http://msdn.microsoft.com/en-us/library/ms740565(VS.85).aspx Oh, and TransmitFile does more than simply load a file into a byte array and send it.
Len Holgate