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
88 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
 Architecture
 On to WinSock
 The Basics
 Socket Types
 Error Checking
 The price you
 pay...

 Rock, Paper,
 Scissor, Shoot!

 How to use
 the demo

 A word on lag
 Conclusion

 Demo
 Printable version

 


Blocking, non-blocking, and asynchronous sockets

Here is where I have to stop for a bit and discuss some more theory. So far we have only been using blocking sockets. When we call accept (), the function just sits there waiting for a connection request to be made. That is what blocking means. The function will just sit there waiting for an event or an error to occur. This type of socket is the default type created with the socket () command.

The next type of socket is the non-blocking socket. With a non-blocking socket, functions such as accept () return immediately after being called, returning either an error, a good result, or nothing (meaning that the result will come in later). These sockets are computationally inefficient as you will find yourself writing tight while loops waiting for some even to finally happen. It is not good practice to use these sockets. Non-blocking sockets can be made using the select () command. I will not show you how to use them since there is a better way of making sockets that don't block.

Asynchronous sockets are Win32 specific. They are sockets that, like non-blocking sockets, return immediately. The difference is that you give the setup function a windows message that it should send when the desired event has occurred. This way you can say:

#define WM_ONSOCKET WM_USER+1 …in message handler… case WM_ONSOCKET: { if (WSAGETSELECTERROR(lparam)) { // error occurred WSACleanup (); return 0; } switch (WSAGETSELECTEVENT(lparam)) { case FD_READ: // data has been received … case FD_CONNECT: // connection has been accepted … } } break;

This is great if you are using MFC or the Win32 API. You can do other things like draw graphics, receive user input, etc. while waiting for some socket event to occur.

What type of socket should I use now?

For server applications, use blocking sockets, as they are the most logical, simple, and practical when all you want to do is wait for a connection and then communicate with the client.

For client applications, use asynchronous sockets, as they are the most efficient when you want to do other things than just sit around and eat CPU cycles.

Using asynchronous sockets

Alright. You know how to make blocking sockets and now its time to learn the best client type socket.

This is the prototype of the function we're interested in:

int WSAAsyncSelect (SOCKET s, HWND hWnd, usigned int wMsg, long lEvent);

SOCKET s should be clear. hWnd is the window handle of your application (which is main_window_handle if you happen to be using André LaMothe's gaming console for DirectX as a framework J). wMsg is which message you want to be sent to your application if the desired event occurs. lEvent specifies the event(s) that will cause WinSock to send wMsg to your application. Here are some flags you can use:

FD_READ - On receiving data
FD_WRITE - The socket is ready to send data
FD_CONNECT - Server has accepted the socket and we're ready to go
FD_CLOSE - The socket has closed

Just OR (|) them together if you want more than one. Note that these are not all the flags you can use, but these are the only really useful ones for client applications.

When you add code to handle your new "socket" event in your application's message handler, you will need to know two macros. WSAGETSELECTERROR () is used to find out if there happened to be an error. WSAGETSELECTEVENT () is used to find what event has triggered the message.

#define WM_ONSOCKET WM_USER+1 …SOCKET s is initialized. We will set it to asynchronous mode… WSAAsyncSelect (s, hWnd, WM_ONSOCKET, (FD_READ | FD_CONNECT | FD_CLOSE)); …in the event handler… case WM_ONSOCKET: { if (WSAGETSELECTERROR(lparam)) { // error WSACleanup (); return 0; } switch (WSAGETSELECTEVENT(lparam)) { case FD_READ: …receive data… case FD_CONNECT: …start sending data… case FD_CLOSE: …quit program… default: …do nothing… } } break;

Get it? Notice how only the lparam parameter and not the wparam is used.




Next : Error checking