Contents |
|
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.
________________________________________________________