Contents

General Design Philosophy

3D Graphics and Sound

Network Communications

Network Communications

Cross-platform network communication is a must for any multiplayer game. Both the Windows and Macintosh operating systems provide libraries for multiplayer gaming (DirectPlay on Windows and NetSprocket on Macintosh), but both are platform-specific and do not allow for cross-platform networking. These libraries are thus useless to the engineer wishing to implement cross-platform multiplayer games. The only alternative is to code directly to the low-level networking libraries. This section describes how to implement UDP (User Datagram Protocol) communications, a part of the standard TCP/IP stack, using the WinSock library on Windows and the OpenTransport library on the Macintosh.

The NetworkMgr class shown in Listing 3 demonstrates the initialization of WinSock and OpenTransport. After starting up the networking library, the NetworkMgr constructor determines the machine’s local IP address. The WinSock library does not provide a direct way of retrieving this address, so we are forced to use the workaround of retrieving the local machine’s name and then resolving that name’s IP address.

Actual communications occur through the NetworkEndpoint class shown in Listing 3. The code given here implements fully asynchronous operation, meaning that data can be sent and received at any time without dependency on a repetitively called servicing function. This is accomplished through the use of a dedicated thread on Windows and an endpoint notification function on the Macintosh.

The Windows version of the NetworkEndpoint constructor creates a UDP socket and binds it to the machine’s local address. A new thread is also created which listens on two event objects. The first event object is configured by the WSAEventSelect function to be set whenever new data arrives (the FD_READ event) and whenever it becomes possible to send data (the FD_WRITE event). The second event is just used to signal that the thread should exit because the NetworkEndpoint class is being shut down. The dedicated thread sleeps until an event occurs, so it has minimal impact on overall game performance.

The Macintosh version of the NetworkEndpoint constructor creates an asynchronous UDP endpoint and assigns it a notification function. The notification function is then called asynchronously to handle the remainder of the initialization and any subsequent network communications. The notification function first receives the T_OPENCOMPLETE event indicating that the endpoint has been created (even this happens asynchronously). At this point, the endpoint is bound to the machine’s local address. The notification function receives the T_DATA event when new data arrives and it receives the T_GODATA event when it becomes possible to send data which may not have been previously sent because the connection was full.

The Send and Receive functions of the NetworkEndpoint class demonstrate how data packets may be sent and received by a WinSock socket or an OpenTransport endpoint. These functions each send or receive a single data packet. It is import to realize that any data that you expect to send across the wire on a heterogeneous network needs to use a consistent byte order. The official byte order of the internet is big endian, and in fact even WinSock requires that you specify IP addresses in big endian byte order. WinSock provides functions such as htonl (Host TO Network Long) which convert between the host byte order and the network byte order (big endian).

Both WinSock and OpenTransport allow you to receive data packets which are larger than the size of your receipt buffer by breaking the packet into multiple pieces. If you know what the maximum size of your packets can be and set your receipt buffer to this size, then any larger packet may be interpreted as invalid data, perhaps a hacker attempt to flood the connection. The Receive function protects against this by implementing a simple oversized packet mechanism which causes it to ignore all of the pieces of any packets that it receives that are larger than the receipt buffer.

It is likely that you will want to preallocate space for a large number of data packets which can later be used to send and receive data. Since these packets are going to be used asynchronously by more than one thread of execution, they need to be protected by some kind of synchronization mechanism such as a mutex. In the Windows environment, where every thread can be preempted by any other thread, it is safe to wait indefinitely to acquire a mutex inside the dedicated send/receive thread. This is not the case on the Macintosh, however, since the notification function is actually part of an interrupt service routine and will never be preempted by the main thread. On the Macintosh, you have no choice but to only attempt to acquire a mutex from within the notification function. If that attempt fails, you must set a flag indicating that a send or receive operating needs to take place at a later time.

Remember that UDP is an unreliable protocol. UDP datagrams are not guaranteed to reach there destination, and when they do get through, are not guaranteed to arrive in the same order in which they were sent. It is up to you to sort out the details of acknowledging the receipt of packets, resending lost packets, and processing packets in the correct order.

For Further Information

Documentation for the WGL library, DirectX, and WinSock can all be found inside the Microsoft Platform SDK, which can be downloaded at

http://msdn.microsoft.com/downloads/sdks/platform/platform.asp

Documentation for the AGL library can be found inside the Apple OpenGL SDK, which is available at

http://developer.apple.com/opengl/

Documentation for the Macintosh Sound Manager is available online at

http://developer.apple.com/techpubs/mac/Sound/Sound-2.html

Documentation for OpenTransport is available online at

http://developer.apple.com/techpubs/mac/NetworkingOT/NetworkingWOT-2.html

The Apple Game Sprockets SDK can be found at

http://developer.apple.com/games/sprockets/download.html

Eric Lengyel is currently a software engineer on the OpenGL team at
Apple Computer. Before joining Apple in 1999, he spent a few years
in the game development industry and continues to sacrifice sleep in
order to code games in his spare time. Eric can be reached at lengyel@apple.com.

________________________________________________________

[Back to] General Design Philosophy