hi,
can someone roughly explain to me how i can send and receive a large file in non-blocking mode? i know for example that in blocking mode you would say something like invoke recv, blah and the program is waiting for the download to complete. but what if u r in non - blocking mode and you want to process the window messages?
i have noticed random's question. A lot of things iam note sure about. for example, if i want to receve a file, under WN_SOCKET->FD_READ what shall i do!? ive noticed its better to receive part by part the file. how do we do that? and also, i would like to add a progress bar to show the remaining download bytes. How, and where shall i update the progressbar?!

thanks to all.
Posted on 2001-11-14 07:01:36 by Unregistered
When a socket is set in asynchronous mode (with WSAAsyncSelect for example), you receive serveral notification messages like FD_READ, FD_WRITE, FD_ACCEPT, FD_CLOSE etc, depending on which you selected with WSAAsyncSelect.

These messages notify you of a specific event that needs to be handled. The description of FD_READ is:
FD_READ: is sent whenever data is waiting on the socket. At this point, receive the data with recv. You'll have to pass the max nr of bytes you want to receive, and this can be more or less than the real size of the data waiting.

Winsock does not send another FD_READ until it's re-enabled. This re-enabling happens when you call recv (or other functions of the same kind). Even when recv failes, or you do not get all the bytes waiting at the socket, the message is re-enabled anyway. So it doesn't matter how many bytes you receive, as winsock will send you a message whenever there's still data left. But remember that it won't send anything until you re-enable it with recv.

For more detailed help, take a look at the winsock programming reference (sock2.hlp, available for download at my site), especially WSAAsyncSelect (lots of info about FD_* here)

So you'll just have to wait for a FD_READ msg, read some bytes, add the received data to your output buffer, update the progress bar (also in the FD_READ handler), and quit the handler so you can wait for the next msg.

Thomas
Posted on 2001-11-14 07:31:59 by Thomas
Greetings Thomas,

so, lets say i am receiving a 4mb file !
on FD_READ I invoke recv, sock , pMem, 4mb (size),0 !

now, this download will take a while. What happens to the other window messages? Will they get processed or will my window look like frozen?!
Also if this is the case, where shall i place my progressbar update call?

thanks.

P.s. Have you got the chance to write that winsock tutorial yet?

p.s2. sorry for the unregister thing..
:alright:
Posted on 2001-11-14 10:34:02 by Ray
You don't want to call recv with a 4mb buffer, but with a smaller buffer ... say 8kb then return ... the window will then receive another FD_READ.
On very big file it's quite inefficient ... as I found out. You better do this:

DISABLE FD_READ with WSAAsyncSelect
loop the recv until you get a SOCKET_ERROR (or a zero = EOF)
RE-ENABLE FD_READ

If you loop the recv without disabling FD_READ, you'll get a lot of "trash" FD_READ messages


Hold on ... here is the M$ words on it, which is better than my crap above ;)

For FD_READ, FD_OOB, and FD_ACCEPT events, message posting is "level-triggerred."
Consider the following sequence:


(i) Windows Sockets DLL receives 100 bytes of data on socket s and posts an FD_READ message.
(ii) The application issues recv( s, buffptr, 50, 0) to read 50 bytes.
(iii) The Windows Sockets DLL posts another FD_READ message since there is still data to be read.


With these semantics, an application need not read all available data in response to an FD_READ message--a single recv() in response to each FD_READ message is appropriate. If an application issues multiple recv() calls in response to a single FD_READ, it may receive multiple FD_READ messages. Such an application may wish to disable FD_READ messages before starting the recv() calls by calling WSAAsyncSelect() with the FD_READ event not set.

Let me know if it makes any sense

Random
Posted on 2001-11-14 10:46:40 by random
Greetings Thomas,

so, lets say i am receiving a 4mb file !
on FD_READ I invoke recv, sock , pMem, 4mb (size),0 !

now, this download will take a while. What happens to the other window messages? Will they get processed or will my window look like frozen?!

It's not a good idea and also useless to set the size param to 4MB, as recv will only put as much as is available at that point into the buffer. Then it will just return and not wait for more.. So unless you have a 1gbit connection, recv will just store as much bytes as it can in the buffer (say 4kb for example), and then return. When the next data part is available, FD_READ will be called again. This is exactly the difference between blocked & non-blocked. A blocked socket would hang on the recv until it has received 4MB, and that would cause a frozen window... But this is non-blocking mode..
Your code would probably cause corrupted data as you assume everything is downloaded in one call, but it isn't.

You should have three variables: pMem for the pointer to the allocated mem (make sure it has the correct size), 4mb in your case, one that holds the nr of bytes already received (nBytesReceived), and one that holds the total number of bytes to be received (nBytesToDo)


before downloading, set pMem and initialize nBytesReceived to zero.
...
on FD_READ:

mov eax, nBytesReceived ;bytes received so far
mov ecx, nBytesToDo ;TOTAL number of bytes to read
sub ecx, eax ; = nr of bytes yet to do
.IF ecx>4096
mov ecx, 4096 ;don't do more than 4KB at a time
.ENDIF
add eax, pMem ;add base pointer
invoke recv, hSock, eax, ecx ;read pending data
.IF eax==0
;connection is closed
.ELSEIF eax==SOCKET_ERROR
;error occurred
.ELSE
add nBytesReceived, eax ;update byte counter
.ENDIF

mov eax, nBytesReceived
.IF eax==nBytesToDo
;download finished
.ENDIF
...


This will add whatever data is pending to the buffer. It will do 4KB at most each time. Note that unlike in blocking mode, this value is just the maximum amount of data you want recv to return. It has no other relation to the amount of data pending or actually returned.. You can remove the IF with the 4096 too, then it would download as much data as possible, but because this is unlikely to happen I use a maximum amount most of the time.

Also if this is the case, where shall i place my progressbar update call?


At the end of the FD_READ message will do.


thanks.

P.s. Have you got the chance to write that winsock tutorial yet?

I started with it and I've written a few chapters on blocking mode winsock and was about to start with non-blocking stuff, but I'm working on two projects now (the oop tool and httpft) and haven't had much time (as usual :( ), but maybe later..


p.s2. sorry for the unregister thing


Well I know who you are now :)

Thomas
Posted on 2001-11-14 10:55:38 by Thomas
Random: I have used the method with calling recv multiple times a long time because I thought that was the right way to do it.. And of course it's perfectly correct but as the doc says...
"With these semantics, an application need not read all available data in response to an FD_READ message--a single recv() in response to each FD_READ message is appropriate. "
... a single will do too and it's a bit easier to implement. So it's more a matter of style if you choose for the multiple recvs or just one.

Thomas
Posted on 2001-11-14 10:58:48 by Thomas
Random:
On very big file it's quite inefficient ... as I found out

I overlooked this in your post the first time I read it .. This may be true.. Instead of the multiple recvs you can use ioctlsocket to determine the amount of data waiting on the socket too. Then one recv would get as much data as possible.. Which is the same as calling recv until it fails.. Maybe that's more efficient..

Thomas
Posted on 2001-11-14 11:03:22 by Thomas
I tried ioctlsocket but doesn't work when you have a very fast stream of data coming in (I tested with various files up to 1Gb on Ethernet 10 and 100Mbit)

ioctlsocket will return a value up to the maximum TCP window anyway (or whatever it's called, can't remember) ... by the time you recv that amount and wait for the (very slow) window message, you have already filled the buffer .. and blocked the sending peer, thus reducing the transfer performance

I think there are 2 ways to saturate the bandwidth and have an efficient transfer of huge files:

1) blocking sockets and threads (it's what I'm using now, after dropping the async sockets ... I'm writing a laplink kind of program and I really just need 1 connection between the server and the client): again .. it's important not to call recv with a big buffer, otherwise you "saturate" the buffer and interrupt the smooth flow of traffic. The right size of the buffer depends on various factors: the speed of the PC, the speed of the network, the NIC on-board memory and the OS settings = a fu**ing nightmare to achieve the maximum performance on all machines

2) Overallapped I/O and completion ports (for a truly scalable server ... say a web or ftp server); haven't tried it yet but will do as soon as I have time to spare, looks very complicated to code correctly though

Remember ... I'm talking about pure transfer speed of big files here.
For normal data traffic, async works great
I've been working around this issue for more than a month, but at least I start getting the performance I expect.

Random
Posted on 2001-11-14 12:37:46 by random


Overallapped I/O and completion ports (for a truly scalable server ... say a web or ftp server);

Actually I am writing a webserver :).. well I'm not trying to rewrite apache or something but nonetheless a full blown web server (with an AHP module :) ) for my httpft program.. Although I don't have much bandwidth on my internet connection I'm interested in the method that delivers the highest performance.. But I don't think I want to be messing with overlapped I/O... The first version of the server (which actually worked) used a combination of threads and asynchronous sockets (with windows messages). I think I'll switch to event sockets now.. there's a function called WSAEventSelect (or SelectEvent, can't remember) which is almost the same as WSAAsyncSelect, but triggers an event object instead of sending a window message. That should be faster than windows messages
I don't like blocking sockets because...well... they block :grin:
I want to have full control all the time and the thread should receive messages from the webserver too, which is already done via a message queue (my own) and a wake-up event.
I didn't know ioctlsocket returned only the maximum tcp window size... I think I switch to multiple recvs back again as well.
When everythings working again I'll try it out on the local 100Mbit network (using WSAEventSelect and multiple recvs until failure) to see how it performs.

Thanks for the information, :alright:

Thomas
Posted on 2001-11-14 13:08:28 by Thomas
Sounds good :)

Only problem of WSAAsyncEvent is that's a new function on winsock 2.0 and will not work on machine with the ver1.1 of the stack (very little of them around anyway)
Actually that's the same problem of overlapped I/O !! eheh

I'm looking forward to see your program in action


Random
Posted on 2001-11-14 13:16:32 by random
I've dumped 1.1 already when I started with the program.. I always import ws2_32.lib instead of wsock32.lib... Iirc, only old win95 versions do not support winsock 2, and for those version a patch is around somewhere... And the docs of wsock2 looked so much better than 1.1 :).
btw I've made a little test program that just keeps outputting bytes (in blocked mode, very simple).. Now I'll try a few client methods to see which performs best.. You can remove the comments above the Crap variable to make a browser get the data (http://yourserver:4444/blah.dat).. but that's not really a good performance test as it also has to be written to disk then..
I'll post the clients as soon as I finished them.
Posted on 2001-11-14 13:45:01 by Thomas
Well, WSAAsyncEvent might only work on winsock2 (which is default
since win98, and can be applied to win95 as a patch)... but overlapped
I/O and completion ports... aren't they nt/2k/xp only?
Posted on 2001-11-14 13:45:19 by f0dder
f0dder: I never used it but all functions that deal with overlapped I/O seem to be supported in both windows & windows NT, according to the docs.

random: The attachments contains the server & 6 clients using different methods.. I didn't have the chance to test it on the local network yet, so I just used localhost for now (but of couse the local network is more interesting..) In client.inc are some general setting you can play with like the IP of the server to connect to, the packet size and the amount of data to be received.. My results with localhost are showed below, but maybe it's totally different with a real network.. I'll try as soon as I can.


1: WSAAsyncSelect
1A: WSAsyncSelect with multiple recvs
2: Blocking mode in thread
3: WSAEventSelect in thrad
4: WSAEventSelect in thread with multiple recvs
5: WSAEventSelect in thread with ioctlsocket

localhost:
1) 256 MB in 4.316 s ( 59.3 MB/s)
1A)256 MB in 5.228 s ( 50.0 MB/s)
2) 256 MB in 2.764 s ( 92.6 MB/s)
3) 256 MB in 1.562 s (163.9 MB/s)
4) 256 MB in 2.784 s ( 92.0 MB/s)
5) 256 MB in 1.813 s (141.2 MB/s)


Thomas
P.S. Don't look at the style of the programs, they are awfully written, just to write them as fast as possible.. the winsock code is correct though. :)
Posted on 2001-11-14 14:46:33 by Thomas
Random, Thomas,

thanks a lot. i'll give it a try and see what happens. And if i mess up again, hey, you will se me again :rolleyes:


:alright:
Posted on 2001-11-15 01:13:42 by Ray
Here are the time for my local network:


1: WSAAsyncSelect
1A: WSAsyncSelect with multiple recvs
2: Blocking mode in thread
3: WSAEventSelect in thrad
4: WSAEventSelect in thread with multiple recvs
5: WSAEventSelect in thread with ioctlsocket

local network (100 Mbit):
1) 256 MB in 60.173 s (4.25 MB/s)
1A)*
2) 256 MB in 49.072 s (5.22 MB/s)
3) 256 MB in 49.334 s (5.19 MB/s)
4) 256 MB in 49.154 s (5.21 MB/s)
5) 256 MB in 50.319 s (5.09 MB/s)

*1A: Program ran out of resources (bug?)


It's clear than WSAAsyncSelect is the slowest, and also important to note here is that 1 is too busy with handling the wsock message that it's window becomes totally frozen...
The others didn't have this problem but they react a bit slow though... The differences for 2-5 are not so big, the localhost test gave some bigger differences. Somehow the 1A test crashed and window told that it was out of resources so there may be a bug there.
Do you know if you can use the full 100Mbit bandwith? That would be 12.5 MB/s but it reaches 5.22 at most... Maybe the tcp/ip overhead is to big.

Thomas
Posted on 2001-11-15 02:16:53 by Thomas
Hm, is megabit meaured in 1000^2 or 1024^2? I think I saw it measured
in 1000^2 a few couple of places?

Anyway, TCP overhead is one thing (try with UDP), the fact that
most network adapters don't reach their full speed is another.
If you have el-cheapo cards like realtek8139 (like me :D), 5MB/s
is sorta OK. I can reach 6-7MB/s at max (my box #2 is a sorta old
machine, so it might get a bit swamped, and the NICs might be able
to go a bit higher).
Posted on 2001-11-15 06:23:51 by f0dder
Hm, is megabit meaured in 1000^2 or 1024^2? I think I saw it measured in 1000^2 a few couple of places?


I did use 1024^2, where did you see 1000?
Posted on 2001-11-15 09:13:22 by Thomas
I can't remember where, but the person seemed to know what he
was talking about, and he wrote that you measure bps (bit per second)
in the traditional 1000-way, instead of the byte-way of 1024...
which confused me a bit, as computer guys are usually very fond of
1024, and the only (other?) place I've seen 1000-measurement is
in harddrive sizes (by the manufacturers), which is clearly a marketing
trick to make their drives appear larger than they are :/
Posted on 2001-11-15 09:23:08 by f0dder
I tested it on my office LAN (should be 100Mbit but god knows how they rigged the servers up) and got around 4Mb/s
Anyway, you can't really expect to reach the full 100Mbits ... I think they normally reach around 70Mbit of actual throughpuy anyway, plus consider that things like quality of hub/switches, NIC, HD etc etc impact the performance ... plus the size of the protocol overhead are important.
Try and test it sending 8kb packets (that's the ethernet size anyway) instead of 4kb ... you should be able to get better results (in my case I improved it by only by 0.5Mb ... but that's because as I said my network sucks :( )

cheers
Random
Posted on 2001-11-16 09:03:18 by random
Protocol overhead isn't all that bad, though it does swallow some.
If you have a direct cross cable between to machines, or a network
with only two machines generating network traffic (and not total
crap equipment), you should be able to reach decent speeds.

And btw, the ethernet packet size is 1500 bytes.
Posted on 2001-11-16 09:12:40 by f0dder