IOCP and WSARecv?

Started by
5 comments, last by laeuchli 22 years, 3 months ago
I want to use IOCP with WSARecv, but my code just isn't working. Does anyone have a example I could see on how to setup WSARecv overlapped? Thanks, Jesse www.laeuchli.com/jesse/ Edited by - laeuchli on August 20, 2001 1:02:56 PM
Advertisement
Hiya,

I have just been doing this my self (or just done ).. here is the basics that you need to know if you have a half working version already.. Note : im using Delphi. I had to convert code from C to Delphi so im sure you can reverse it back to C ;-)

WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_IP, Nil, 0, WSA_FLAG_OVERLAPPED);

Result := AcceptEx(
aSocket,
g_pCtxtListenSocket.pIOContext.SocketAccept,
@(g_pCtxtListenSocket.pIOContext.Buffer[0]),
MAX_BUFF_SIZE - (2 * (sizeof(SOCKADDR_IN) + 16)),
sizeof(SOCKADDR_IN) + 16,
sizeof(SOCKADDR_IN) + 16,
dwRecvNumBytes,
@(g_pCtxtListenSocket.pIOContext.Overlapped)
);

Note g_pCtxtListenSocket.pIOContext.Overlapped is of type WSAOVERLAPPED ( or _OVERLAPPED its the same) also note @ meens "return pointer to..."

nRet := WSARecv(
lpAcceptSocketContext.Socket,
@buffRecv,
1,
@dwRecvNumBytes,
@dwFlags,
@lpAcceptSocketContext.pIOContext.Overlapped,
Nil);

note the important part is that you pass the overlapped structure


hope that helps

-Tim (no a pro at this.. like i said just finished my 1st version of it)
~ Tim
I see my email has served you well, wrathgame .

Now, go forth and conquer...hehe.
BTW Wrath one thing you may want to be careful about:

When you call AcceptEx and specify a value for dwRecvDataLength, a IOCP packet will *not* be queued until the client actually sends some data. This can be very annoying so what I do is specify a value of zero for dwRecvDataLength. You still MUST specify a buffer large enough to hold the local and remote addresses (unless under Windows 2000 - but I found that doesn''t cause an IOCP packet to be queue either - weird).

So I typically make my AcceptEx calls like this:

char buffer[(sizeof(SOCKADDR_IN) + 16) * 2)];AcceptEx(aSocket,         g_pCtxtListenSocket.pIOContext.SocketAccept,         buffer,         0,         sizeof(SOCKADDR_IN) + 16,         sizeof(SOCKADDR_IN) + 16,         dwRecvNumBytes,         &g_pCtxtListenSocket.pIOContext.Overlapped         ); 


If you clients send data immediately (like in a client to web-server transaction) then passing a data buffer to AcceptEx is a good idea

If you are looking to extract the local and remote addresses from the buffer you pass to AcceptEx call:

GetAcceptExSockaddrs

Damn, I better get back to my day job.

Take care,



Dire Wolf
www.digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Hi Wolf,

>>I see my email has served you well, wrathgame

yup, thanks for all the advice u gave me :-)

<<
When you call AcceptEx and specify a value for dwRecvDataLength, a IOCP packet will *not* be queued until the client actually sends some data. This can be very annoying so what I do is specify a value of zero for dwRecvDataLength. You still MUST specify a buffer large enough to hold the local and remote addresses (unless under Windows 2000 - but I found that doesn''t cause an IOCP packet to be queue either - weird).
>>

Yeh i already worked that out but thanks.. I am specifying a buffer (i just thought it would be best.. wasnt sure if it was being used for the local abd remote details). I am using win 2K.. what do u mean by "I found that doesn''t cause an IOCP packet to be queue either " ?

>>If you are looking to extract the local and remote addresses from the buffer you pass to AcceptEx call: GetAcceptExSockaddrs

::nods:: i just this sec worked that one out ;-) thanks

-Tim
~ Tim
Hmm... ok new problem..

How do i do a graceful shutdown on a client ?? all i can get to work is closeSocket .. and that raises an error on the client (yes i could catch it and ignore it on the client but thats lazy ) and also it would be nice to re-use sockets and store them in a pool so i dont really want to free it

thanks

-Tim
~ Tim
Socket reuse is not specifically supported under the current Winsock 2 implementation. It is up to the Winsock provider (of the IP stack and WSPI interface) to allow reuse of sockets.

I tried to figure this one out on my own as well. I would perform a shutdown() request and not close the socket. Then I would pass the socket to AcceptEx and nothing would happen.

If you can find a way to do it (which I don't think you can under Windows) let me know. The idea of creating a pool of sockets is a great idea because you don't have to keep calling socket(...)/WSASocket(...) which can be relatively expensive.

OK now to address your problem:

Firstly, the correct way to handle IOCP GetQueuedCompletionStatus calls is this way:

      while(true){BOOL  result    = GetQueuedCompletionStatus(...);DWORD lasterror = GetLastError();if(result){    if(bytes_transferred == 0 && (pContext->IOOperation != IOAccept))    {        // client gracefully disconnected        // might as well close the socket here        closesocket(clientsocket);        continue;    }    switch(pContext->IOOperation)    {        case IOAccept:        // blah blah blah    }}else{    if(pOverlapped != NULL)    {        // IO request failed for some reason        // Most likely the client abruptly disconnected        // You should close the socket handle here...        // and perform any "error handling" too.        // The reason for the IO failure is in 'lasterror'        // note:  the IO context you stored is still valid        //        i.e. returned in call to GetQueuedCompletionStatus    }    else    {        if(lasterror == WAIT_TIMEOUT)        {            // IO GetQueuedCompletionStatus timedout        }        else        {            // a REAL error occurred.        }    }}} // while(true)  


The graceful way to shutdown your connection with the client is as follows:

  shutdown(clientsocket, 2);  // gracefully shutsdown socketclosesocket(clientsocket);  // frees sockethandle and resources      


Calling closesocket without calling shutdown first performs a hard-close of the virtual connection and frees system resources.
You need to call shutdown first.

Hopefully this explains everything

Best regards,



Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on August 23, 2001 12:53:37 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
How do you tell what the address of the local receive socket is?

The remote addr from GetAcceptExSockaddrs is correct, but the local addr returns the listening port - I was expecting a new port to be assigned to the recv socket.
and calling getsocketname on the recv socket returns all 0''s.

...
The latest Platform SDK adds two new WinSock functions (among others), ConnectEx and DisconnectEx - the former is an an asyncronous IO connection function in the typical format and the later allows socket reuse. Unfortunetly they appear to only be available on XP.

- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

This topic is closed to new replies.

Advertisement