Hi All,

I've got a question that has been bugging me for some time now.
I'm writing a small app that allows file transfers between PCs on a intranet / LAN (a bit like LapLink or PCAnywhere, but just on TCP/IP)

The app works fine when the 2 PCs have similar speeds. The problem arises when one of the 2 is considerably slower. What happen is the infamous Silly Window Syndrome, where one PC is sending data faster than the receiver can read, therefore filling the receiver buffer too quickly (or something like that). And when this happens the program on the slow receiving machine freezes until the whole file is transferred (not very professional is it?)

I've been using async sockets on both the server and the client.
I've been playing around a lot with various combinations (like file mapping, multiple recv vs single recv, single/multi-threads, different recv/sending buffer sizes, etc) and the following is for the moment the best I've got

Here is part of the code for the server / sending routine (placed on a dedicated thread):

;*********************************************
when receive FD_WRITE and file transfer is in progress then call:
....
invoke SetFilePointer,,,0,FILE_BEGIN
;//start sending loop
xor eax,eax
.WHILE !=0 && eax!=SOCKET_ERROR
mov eax,8192 ;//8kb sending buffer
.IF eax>
mov eax, ;//transfer final chunk
.ENDIF
mov ecx,eax
invoke ReadFile,,,ecx,ADDR num,0
invoke send, , , , NULL
.IF eax!=SOCKET_ERROR
sub ,eax
add ,eax
.IF ==0 ;//transferred the whole file
...
...//closes handles, etc....
...
.ELSEIF eax!= ;//if couldn't send all data
invoke SetFilePointer,,,0,FILE_BEGIN
.ENDIF
.ELSE ;<An error occured>
...
...//handle the error
...
.ENDIF
.ENDW

...if the file transfer is not over, will wait for FD_WRITE
;*********************************************



On the client side / receving routine I have:

;*********************************************
when receive FD_READ and file transfer is in progress then call:
....

;//disable FD_READ message because
;//multiple recvs will prompt multiple FD_READ
invoke WSAAsyncSelect, , , WM_SOCKET_CLIENT, FD_CLOSE+FD_WRITE
;//start receiving loop
xor eax,eax
.WHILE !=0 && eax!=SOCKET_ERROR
invoke ioctlsocket,,FIONREAD,ADDR
mov eax,
.IF eax>
mov eax, ;//transfer final chunk
.ENDIF
.IF eax>8192 ;//8kb receiving buffer
mov eax,8192
.ENDIF
invoke recv, ,, eax, NULL
.IF eax!=SOCKET_ERROR
sub ,eax
add ,eax
mov ecx,eax
invoke WriteFile,,,ecx,ADDR ,0
.IF ==0 ;//reached EOF
...
...//closes handles, etc....
...
.ENDIF
.ELSE ;<An error occured>
...
...//handle the error
...
.ENDIF
.ENDW
;//re-enable FD_READ message
invoke WSAAsyncSelect, , , WM_SOCKET_CLIENT, FD_READ+FD_CLOSE+FD_WRITE

...if the file transfer is not over, will wait for FD_READ
;*********************************************


I've tried using a single recv and wait for subsequent FD_READ, but it's worse
Looping the recv seems the fastest receiving way (as long as you disable FD_READ during the loop to avoid windows posting many useless FD_READ)
File mapping is good but when transferring various huge files at the same time the memory requirements are huge as well
Bigger buffers will deteriorate the performance of the transfer FROM the slow TO the fast machine

If the client/receiver is on the slow machine the program will not give me control until the file is transferred.
On small files it's no big deal, but when transferring 1GB files then it's a big issue

On P2P applications where you can transfer many files, very fast without the system loosing in performance and CPU loads around 2% ... how do they do that? say EDonkey or DirectConnect

Any help would be greatly appreciated

Cheers
Random
Posted on 2001-10-16 04:27:51 by random
You should try to work your recv portion
of your program into a thread, there by
letting your main window free to take
care of other chores, such as, updating
your main window, and other functions.
but remember to keep messages going
to and from your thread, so you keep
control at all times.


Zcoder.....
Posted on 2001-10-29 05:43:43 by Zcoder
Zcoder,

thank you
since this post I actually did exactly what you are suggesting.

I now have a pool of 4 working threads:

The main window thread, which receives all messages and forwards all winsock messages (FD_READ/WRITE etc) to a "Winsock" thread. This thread handles the winsock messages and in particular sends FD_READ requests to a READ thread and FD_WRITE req to a WRITE thread, while it deals with everything else. Performance and CPU load have improved considerably, and of course the UI doesn't freeze anymore :)

cheers
Random
Posted on 2001-10-30 04:29:58 by random