Neat little trick

| | Comments (2)

So here's a neat little trick that I just now realized is possible due to RB2006r1. People have asked me in the past what the file i/o handle getter and setter are good for, and I've shown some pretty neat tricks to do with it (such as using it for creating shared memory files). This is another one of those neat tricks.

In WinSock, on NT versions of Windows, there's an API called TransmitFile, which, as the name implies, will transmit a file for you in relatively efficient manner.

Essentially, you give the API a socket handle and a file handle and it'll send the contents of the file over the socket. You can do some other neat tricks with it (like send data before sending the file, and send data after sending the file) as well.

So check this out...
[rbcode]
#if TargetWin32
Declare Function TransmitFile Lib "Mswsock" ( handle as Integer, otherHandle as Integer, _
bytesToWrite as Integer, bytesInSend as Integer, null as Integer, buffers as Integer, _
flags as Integer ) as Boolean

Const TF_DISCONNECT = &h1

MsgBox CStr( TransmitFile( TCPSocket2.Handle, bs.Handle( BinaryStream.HandleTypeWin32Handle ), _
0, 0, 0, 0, TF_DISCONNECT ) )
#endif
[/rbcode]
That's all it takes. You've already got access to a socket handle, so that's the first parameter. And now you have access to the Win32 HANDLE object for file streams, so that's the second parameter.

I made a little sample project to demonstrate this. It's rather worthless in its current form, but with a small amount of modification, it can be very powerful. Basically, it makes a listening socket whose sole job in life is to write data to a file called Test that lives on the Desktop. The other socket (TCPSocket2) connects to the first socket (TCPSocket1) and uses TransmitFile to send a file that the user chose (via GetOpenFolderItem).

This project will need modification to be useful for you since I just have the IP address of where to connect to hardcoded. But monkey around with it a bit, I think you'll like what you see.

So I did a little benchmarking... hah. I sent a 136 MB mp3 file (isn't techno wonderful?) on a 100 MBps LAN.

TransmitFile utilized 2% of the pipe and took 13 minutes and 31 seconds
FileXfer utilized 20% of the pipe and took 1 minute 5 seconds

So writing your own transfer code will prove to work faster if you're sending large amounts of data. I guess TransmitFile isn't quite as efficient as MSDN claims it to be (though in fairness, it does say that Windows Server products will send much faster than Workstation products; and I am running XP which is a Workstation).

2 Comments

A great example of why all those handles are handy!

They really are! But I think a better example was the one I stumbled upon in the RB2006r1 features article I wrote. Holy moly is random access insanely fast with memory mapped files!

Leave a comment

Disclaimer

I'm currently an employee of REAL Software. My blog is mine. The opinions represented in this blog are mine as well and may not represent my employer's opinions. All original material is copyrighted and property of the author.

REALbasic® is a registered trademark of REAL Software, Inc. REAL SQL Server™ and Lingua™ are pending trademarks of REAL Software, Inc. All rights reserved.