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
62 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
 Data Packets
 Multicasting
 in Games


 Source code
 Printable version
 Discuss this article

Joining a Multicast Group and Receiving Multicast Data Packets

To receive multicast packets sent to a multicast group, your game will need to join or become a member of that multicast group. To request becoming a member of a multicast group is a lot simpler than you may at first imagine. You need to first bind() your UDP socket to a local port (elementary, my dear friend):

SOCKADDR_IN addrLocal;
// We want to use the Internet address family
addrLocal.sin_family = AF_INET;
// Use any local address
addrLocal.sin_addr.s_addr = INADDR_ANY;
// Use arbitrary port - but the same as on other clients/servers
addrLocal.sin_port = htons(uiPort); 
// Bind socket to our address
if(SOCKET_ERROR == bind(hUDPSocket, (LPSOCKADDR)&addrLocal, 
                        sizeof(struct sockaddr)))
  {cout << "Euston, we have a problem";}
// Ready to switch to multicasting mode

And then just make a call to setsockopt(), and here's a prototype for your convenience *grin*:

int WSAAPI setsockopt(SOCKET s, int level, int optname,
                      const char FAR * optval, int optlen);

If you thought you were getting away with just 1 new line of code to learn, you were wrong... you're only getting away with 4 new lines =). There are special parameters to prepare for this call: s is your socket handle, level should be set to IPPROTO_IP, optname should be set to IP_ADD_MEMBERSHIP and a pointer to the p_mreq structure passed as optval, with its length in optlen. This is what the p_mreq structure looks like:

struct ip_mreq {
  struct in_addr imr_multiaddr;   /* multicast group to join */
  struct in_addr imr_interface;   /* interface to join on    */
}

It has 2 fields, both of them are in_add r structures: imr_multiaddr specifies the address of the multicast group to join and imr_interface specifies the local address INADDR_ANY.

There are special (Class 'D') addresses allocated for multicast groups. These are in the range from 224.0.1.0 to 239.255.255.255. You can choose an address from the range as the target multicast group to join, and set the imr_multiaddr to this address. The full setsockopt() call would look something like this:

struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
mreq.imr_interface.s_addr = INADDR_ANY;
nRet = setsockopt(hUDPSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                  (char*)&mreq, sizeof(mreq));

And that's all there is to it, apart from a lot of error checking which I've decided to leave out for clarity (aka Laziness). The socket will now receive data packets sent to the multicast group on the specified port with calls to recvfrom():

SOCKADDR_IN addrSrc;
nRet = recvfrom(hUDPSocket, (char *)&Data, sizeof(Data), 0,
                (struct sockaddr*)&addrSrc, sizeof(addrSrc));

When you're finished with the group and want to leave, just repeat the call with identical parameters apart from IP_ADD_MEMBERSHIP which should be replaced with IP_DROP_MEMBERSHIP.

nRet = setsockopt(hUDPSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
                  (char*)&mreq, sizeof(mreq));

Now that we can join a multicast group and receive packets sent to it, the logical thing to do is to learn how to send packets to a multicast group.

Sending Multicast Data Packets

Sending multicast data packets is accomplished with a call to sendto(), specifying a multicast group address as the destination IP address and the wanted port (on which your clients are tuned to listen for data). So there really a lot to learn apart from using the TTL (Time To Live) socket option.

All IP packets carry a TTL value to make sure that they are discarded if they don't reach a destination so they don't clog up the Network. In a multicast data packet, TTL specifies how far a multicast data packet can travel:

TTL ThresholdDescription
TTL equal to 0Restricted to the same host
TTL equal to 1Restricted to the same subnet
TTL equal to 32Restricted to the same site
TTL equal to 64Restricted to the same region
TTL equal to 128Restricted to the same continent
TTL equal to 255Unrestricted in scope
[From MSDN, this is very rough and should not be taken literally]

Multicasting is nowhere as dangerous as broadcasting in terms of unwanted traffic that it can produce but caution is advised when using some of the higher TTL values.

To set a socket's multicast TTL value, setsockopt() can be used with IPPROTO_IP as the protocol level and IP_MULTICAST_TTL as the socket option.

char TTL = 32 ; // Restrict to our school network, for example
setsockopt(hUDPSocket, IPPROTO_IP, IP_MULTICAST_TTL,
           (char *)&TTL, sizeof(TTL));

We must also tell the system exactly which local network interface we would like to multicast on.

// Set the local interface from which multicast is to be transmitted
unsigned long addr = inet_addr(YOUR_IP_ADDRESS_STRING);
setsockopt(sSocket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr,
sizeof(addr));

Once the TTL and multicast interface are set, just sendto() away:

SOCKADDR_IN  addrDest;
szHi[50];

addrDest.sin_family = AF_INET;
// Target multicast group address
addrDest.sin_addr.s_addr = inet_addr("234.5.6.7");
// Port on which client is set to receive data packets
addrDest.sin_port = htons(uiPort);
// Something unoriginal to send
strcpy(szHi,"Hello Multicast Group!");

nRet = sendto(hUDPSocket, (char *)szHi, strlen(szHi), 0,
              (struct sockaddr*)&addrDest, sizeof(addrDest));

We can now join multicast groups, send and receive data from them, but how do we implement multicasting as an option in our game and what would we use it for?



Next : Multicasting in Games