Hello,

I got problem with non-blocking socket:


@Wait4Cmd:
invoke recv,hClient,offset cmdbuffer,sizeof cmdbuffer,0
cmp eax,SOCKET_ERROR
je @BlockCheck
jmp @Commands
@BlockCheck:
invoke WSAGetLastError
.if eax == WSAEWOULDBLOCK
jmp @Wait4Cmd
.endif
jmp @Wait4Connect

This code give 100% of CPU, why?
Before that I made it non-blocking like this:


@Wait4Connect:
invoke accept,hSocket,offset sin,offset sinlen
cmp eax,INVALID_SOCKET
je @Wait4Connect
mov hClient,eax
invoke ioctlsocket,hClient,FIONBIO,addr sockopt

Everything was ok b4 ioctlsocket
Any solution for this?
Posted on 2004-03-15 08:56:43 by zabnik
You could use some method of getting signalled when the socket is actually ready for read/write, like the portable select() or the winsock WSAEventSelect() or - if you must - WSAAsyncSelect().

If not and you continue your polling loop, insert a Sleep() statement to reduce CPU usage. Either a Sleep(0) which means "give up the remainder of the timeslice", or perhaps something like 50ms.
Posted on 2004-03-15 09:17:24 by f0dder
... sorry I forgot to say that this app has no gui (console)
The "sleep" idea is working, thanks
Posted on 2004-03-15 10:10:09 by zabnik
GUI isn't a requirement for using select() or WSAEventSelect, only for the WSAAsyncSelect... and you could always register an invisible window if you *really* want to use that form, even from a console app.
Posted on 2004-03-15 10:16:59 by f0dder
Soemthing like


WaitNextEvent:
lea eax, [hEvent]
invoke WSAWaitForMultipleEvents,1,eax,FALSE,-1,TRUE
lea eax, [myevent]
invoke WSAEnumNetworkEvents,esi,[hEvent],eax
mov eax, [myevent.lNetworkEvents]
test [myevent.lNetworkEvents], FD_READ
jz .notfdread
invoke ioctlsocket,esi,FIONREAD,cbdata
inc eax
jz WaitNextEvent
call [GetProcessHeap]
invoke HeapAlloc,eax,0,[cbdata]
xchg edi, eax
invoke ws_recv, esi, edi, [cbdata],0
stdcall HandleChannel, edi,[lparam]
call [GetProcessHeap]
invoke HeapFree, eax, 0, edi
.notfdread:
test [myevent.lNetworkEvents], FD_CLOSE
jz WaitNextEvent
EndEvent:
invoke WSACloseEvent,[hEvent]
Posted on 2004-03-15 10:50:27 by roticv
Thats complete winsock2 :(

What about select?


.data
fdset fd_set <>
.code
@@:
mov [fdset.count],1
m2m [fdset.array],[hSocket]
invoke select,0,offset fdset,0,0,100 ; timeout in ms?
or eax,eax
jz @B

invoke recv,[hSocket],offset buffer,sizeof buffer,0
; ....
Posted on 2004-03-15 11:07:09 by zabnik
Pretty okay code, roticv - just a couple of questions, though:

Why "xchg edi, eax" instead of "mov edi, eax"?

Why the ioctlsocket(FIONREAD) and HeapAlloc overhead? Wouldn't it be smarter to use a fixed-size local buffer? Would save HeapAlloc overhead and such... The recv call should work fine when specifying a larger buffer (and return the amount of bytes read), and doing it your way isn't really an excuse for doing error handling after the recv :p.

But all in all, it looks like an okay way of doing stuff, although it's probably a bit overkill for a single socket :)

zabnik, the timeout value for select() is a TIMEVAL structure, which has two DWORD entries: tv_sec and tv_usec - value in seconds and microseconds. Thus, to wait for 50 msec, clear the tv_sec value and store 50000 for tv_usec.
Posted on 2004-03-15 14:01:18 by f0dder
Hi f0dder,

1) I think xchg is much more cool than mov :grin:

2) I used that because I do not know what is the size of the pacvket that I am supposed to receive therefore the use of ioctlsocket and Heap overhead.
Posted on 2004-03-15 23:01:01 by roticv
1) silly :grin:

2) appropriately sized LOCAL buffer will handle this. You cannot depend on getting full "packets" anyway, so if your scheme is "packet" based you'll need some form of "packet reassembly" code anyway... Imo it's better sending off the local buffer + bytes received to the "packet reassembly" function and have that add to a heapalloc buffer. Saves you the overhead of constant heapalloc+heapfree. (Also, theoretically, more bytes could have appeared on the socket between the ioctlsocket call and the recv - though that probably is very theoretical ;)).
Posted on 2004-03-16 04:41:51 by f0dder
re packet reassembly code:
Each socket is associated with an event object via WSAEventSelect, and the eventhandles are stored in an array and monitored via WSAWaitForMultipleEvents.
I keep a dynamic buffer per active socket.
The socket monitoring thread recvs data into a local buffer (heapmem, allocated after a call to ioctlsocket, same as you).
I then immediately append the local buffer to the end of the appropriate socket buffer, free the local buffer, then I check if there's at least one "full packet" in the front of that socket buffer (my packets have a PacketSize field).
As long as there is one full packet in the front of the buffer, I split it off and hand it to a processing function, doing that in a loop to empty the buffer of all "full packets", possibly leaving one incomplete packet remaining in the buffer awaiting the next recv.
This totally solved the issue of "sandwich packets" caused by overzealous network stacks and by routers splitting packets.

Comments?
Posted on 2004-09-07 01:05:32 by Homer
run everything through a debugger, and make sure you don't have a thread looping recv() on an empty/already-closed socket. make sure that when you error-check for recv() and send(), you have to take into account both SOCKET_ERROR (-1) and 0 (no data is received). debugging winsock applications can be a pain, but i've found out that several times when my apps failed for some weird reason, and started to eat 100% CPU, it was due to inadequte error-checking in recv (it kept looping in the thread, and thread was never closed).

just my 2 cents.
Posted on 2004-09-07 16:13:48 by Drocon