Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
79 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Introduction
 Setting Up
 Notification
 Messages

 Shaking Hands
 Sending and
 Receiving


 Printable version
 Discuss this article
 in the forums


Handling Notification Messages

Notification Messages is really a misleading term. In reality, WinSock only generates one message that it posts to the queue, and attached to it is the event that occurred. This is shown by the example below.

switch(msg)
{
case WM_WSAASYNC:
  {
    // what word?
    switch(WSAGETSELECTEVENT(lParam))
    {
    case FD_ACCEPT:
      {
        // check for an error
        if (!WSAGETSELECTERROR(lParam))
          return(FALSE);
        // process message
        sAccept =  accept(wParam, NULL, NULL);
          return(0);
      }
    }
  }
}

Whoa! Talk about nests! And what are all these macros doing? LParam and wParam? What the heck? Let’s now take a look at the notification message structure

WParam lParam
  HIWORD
WSAGETSELECTERROR()
LOWORD
WSAGETSELECTEVENT()
socket instance 0 if successful, else an error code value that can be called for using WSAGetLastError() WinSock event such as FD_READ, FD_WRITE, FD_CLOSE, etc.

Ahhh, now it’s beginning to make some sense. Let’s cover where each parameter plays its part. We’ll start with wParam. Where is it? Right here:

...
sAccept = accept(wParam, NULL, NULL);
...

And here’s what I was telling you earlier. Notice I used the variable wParam in place of the socket instance. Why? So that if I had more than one socket (s1 and s2) I could use the same message for both. So whichever socket invokes the message is passed along with it. For instance, say it was s2 that needs to receive data. Well instead of having a switch statement inside the message handler to decide which socket to place in the accept() call, I just use wParam. Translation:

sAccept = accept(wParam, NULL, NULL);

is equal to

sAccept = accept(s2, NULL, NULL);

Now that is cool. Saves you the time and the trouble now doesn’t it? I know I probably repeated myself a bit there but it’s an important point to remember and understand because it’s very useful, as you can see.

Now then, lParam is no more complicated. But there is a difference. The lParam variable has a high field and a low field, and both fields can be set to separate values. Normally we would extract these with the Windows’ API HIWORD() and LOWORD() macros. But Winsock makes our lives even easier and has two of its own macros, WSAGETSELECTEVENT() and WSAGETSELECTERROR(). These do the exact same thing as the Windows’ macros, except they relieve us of the need to remember which field holds what. If you look back up at the example above, you can see how both macros are used. The WSAGETSELECTEVENT() is your ticket to figuring out just what WinSock event was triggered. Here is the full case statement inside the WM_WSAASYNC message handler:

switch(WSAGETSELECTEVENT(lParam))
{
case FD_READ:
  {
  } break;
case FD_WRITE:
  {
  } break;
case FD_CONNECT:
//     or
case FD_ACCEPT:
  {
  } break;
case FD_CLOSE:
  {
  } break;
}

Hope I didn’t trip you up with the FD_CONNECT and the FD_ACCEPT events - just remember that they will always depend on whether it’s the server or the client.

And finally we have the WSAGETSELECTERROR() macro, which we can use to see if an error has occurred before we decide to do anything. Usually this is not necessary, but there is one good time to error check - and that’s when the FD_CLOSE event is called. As I said earlier, there are many reasons a socket could be shut down. Here are the error codes:

  • 0 = either the other side did a graceful close or did a shutdown() for send. Either way there was no real error.
  • WSACONNRESET = the other side did a closesocket() with reset close behavior.
  • WSACONNABORTED = the connection may have timed out. This is an abrupt abort and could even be from the user just quitting.
  • WSANETDOWN = network code has completely failed, which means you’re in trouble J

It’s always best to check for these error codes when processing an FD_CLOSE event to determine just what went wrong. All other times you should just use the WSAGetLastError() function to determine what went bad.





Next : Shaking Hands