< IPv4 & Multicast Sourcing | Multicasting Main | Reliable Multicasting >


 

 

Multicasting 9 Part 4

 

 

What do we have in this chapter 9 part 4?

  1. IPv6

  2. Sending Multicast Data with IPv4

  3. Sending Multicast Data with IPv6

  4. Multicasting with WSAIoctl()

  5. Multicasting with WSAJoinLeaf()

 

IPv6

 

Multicasting with IPv6 is similar to IPv4 multicasting except that the socket options are named differently and take slightly different input parameters. The options for IPv6 are IPV6_ADD_MEMBERSHIP and IPV6_DROP_MEMBERSHIP. The option level is IPPROTO_IPV6. The structure that specifies the multicast group and interface is a struct ipv6_mreq that is defined as:

 

typedef struct ipv6_mreq {

    struct in6_addr ipv6mr_multiaddr;  /* IPv6 multicast address */

    unsigned int    ipv6mr_interface;  /* Interface index */

} IPV6_MREQ;

 

The structure fields are equivalent to the IPv4 structure struct ip_mreq except that the local interface is the interface index instead of the full IPv6 address. The easiest way to find the interface index of a local IPv6 address is via the IP Helper API GetAdaptersAddresses(). Also, if the link-local address is used as the local interface, the scope-ID of that link is the interface index. The following code sample illustrates joining an IPv6 multicast group when the link-local address is given for the local interface:

 

SOCKET             s;

struct ipv6_mreq   mreq6;

struct addrinfo   *reslocal, *resmulti, hints;

 

s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);

 

// Get the local wildcard address to bind to (i.e. "::")

memset(&hints, 0, sizeof(hints));

hints.ai_family = AF_INET6;

getaddrinfo(NULL, "5150", &hints, &reslocal);

bind(s, reslocal->ai_addr, reslocal->ai_addrlen);

freeaddrinfo(reslocal);

 

// Resolve the link-local interface

getaddrinfo("fe80::250:4ff:fe7c:7036%6", NULL, NULL, &reslocal);

// Resolve the multicast address

getaddrinfo("ff12::1", NULL, NULL, &resmulti);

 

// Join the multicast group

mreq6.ipv6mr_multiaddr = ((SOCKADDR_IN6 *)resmulti->ai_addr)->sin6_addr;

mreq6.ipv6mr_interface = ((SOCKADDR_IN6 *)reslocal->ai_addr)->sin6_scope_id;

 

setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&mreq6, sizeof(mreq6));

 

freeaddrinfo(resmulti);

freeaddrinfo(reslocal);

 

As with IPv4, to leave the multicast group the same struct ipv6_mreq structure is passed into setsockopt() but with the IPV6_DROP_MEMBERSHIP option.

 

Sending Multicast Data with IPv4

 

The previous sections have shown how to join and leave multicast groups to receive data sent to that group; however, an application need not join the group to send data to it. There is one issue to be aware of: multihomed computers. If an application creates a UDP socket and calls sendto() with a destination address of “234.5.6.7”, which interface is the data sent on? Basically, the first interface listed in the routing table is the interface the data is sent on. To override this behavior, applications may use the IP_MULTICAST_IF socket option to specify the interface for outgoing data. The option value is simply the 32-bit IPv4 address of the local interface. The following code sample sets the outgoing interface on a socket.

 

SOCKET         s;

SOCKADDR_IN    dest;

ULONG          localif;

char           buf[1024];

int            buflen=1024;

 

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

 

localif = inet_addr("157.124.22.104");

setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, (char *)&localif, sizeof(localif));

 

dest.sin_family = AF_INET;

dest.sin_port   = htons(5150);

dest.sin_addr.s_addr = inet_addr("234.5.6.7");

 

sendto(s, buf, buflen, 0, (SOCKADDR *)&dest, sizeof(dest));

 

Sending Multicast Data with IPv6

 

The same sending issue that applies to IPv4 is also present for IPv6 multicasting. The outgoing interface for data sent to an IPv6 multicast group is specified with the IPV6_MULTICAST_IF option. The input parameter is an integer that specifies the adapter interface index that outgoing data is sent on. Also, if sendto() or WSASendTo() is used for sending data to the multicast group, the sin6_scope_id of the SOCKADDR_IN6 structure given for the to address parameter should be zero.

 

Multicasting with WSAIoctl()

 

For IPv4 source multicasting, there is an ioctl that can specify one or more source addresses to include or exclude with a single call. This is SIO_SET_MULTICAST_FILTER. The input parameter is a struct ip_msfilter structure that is defined as:

 

struct ip_msfilter {

   struct in_addr imsf_multiaddr;  /* IP multicast address of group */

   struct in_addr imsf_interface;  /* local IP address of interface */

   u_long         imsf_fmode;      /* filter mode - INCLUDE or EXCLUDE */

   u_long         imsf_numsrc;    /* number of sources in src_list */

    struct in_addr imsf_slist[1];

};

 

The first two fields are self-explanatory. The third field, imsf_fmode, indicates whether the source addresses listed in the imsf_slist array are sources that should be included or excluded from the multicast group. To include the sources, the constant MCAST_INCLUDE is supplied; otherwise, to exclude these sources MCAST_EXCLUDE is used. imsf_numsrc indicates the number of sources supplied, and imsf_slist is the array of source addresses. The following code sample illustrates using this ioctl:

 

SOCKET                    s;

char                 buf[1024];

struct ip_msfilter *msfilter;

DWORD                     bytes;

int                                filterlen;

 

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

 

// bind the socket to INADDR_ANY

msfilter = (struct ip_msfilter *)buf;

msfilter->imsf_multiaddr.s_addr = inet_addr("234.5.6.7");

msfilter->imsf_interface.s_addr = inet_addr("157.124.22.104");

msfilter->imsf_fmode = MCAST_INCLUDE;

msfilter->imsf_numsrc = 3;

msfilter->imsf_slist[0].s_addr = inet_addr("172.138.104.10");

msfilter->imsf_slist[1].s_addr = inet_addr("172.138.104.11");

msfilter->imsf_slist[2].s_addr = inet_addr("172.138.104.12");

 

filterlen = sizeof(struct ip_msfilter) + ((msfilter->imsf_numsrc - 1) * sizeof(struct in_addr));

 

WSAIoctl(s, SIO_SET_MULTICAST_FILTER, (void *)msfilter, filterlen, NULL, 0, &bytes, NULL, NULL);

 

This sample joins a multicast group and specifies three valid sources to accept data from. To retrieve the multicast filter set, use the ioctl SIO_GET_MULTICAST_ FILTER. The input parameter must be a struct ip_msfilter structure that contains the local interface and multicast group on which to obtain the multicast state for. Upon success, a struct ip_msfilter structure is returned via the output parameter, which contains the full set of sources for the group and interface. Note that you must specify a large enough buffer to hold the filter plus all the sources.

 

Multicasting with WSAJoinLeaf()

 

Winsock 2 introduces the WSAJoinLeaf() API, which is designed to be protocol independent. The API is defined as:

 

SOCKET WSAJoinLeaf(

    IN SOCKET s,

    IN const struct sockaddr FAR * name,

    IN int namelen,

    IN LPWSABUF lpCallerData,

    OUT LPWSABUF lpCalleeData,

    IN LPQOS lpSQOS,

    IN LPQOS lpGQOS,

    IN DWORD dwFlags

    );

 

In most respects, WSAJoinLeaf() takes the same parameters as WSAConnect(). The exceptions are that name indicates the multicast address to join and dwFlags indicates whether the socket will be sending or receiving data on the multicast socket. The valid flag values are JL_SENDER_ONLY, JL_RECEIVER_ONLY, and JL_BOTH.

For IP multicasting, a UDP socket must be created by using the WSASocket() API, and the flags WSA_FLAG_MULTIPOINT_C_LEAF and WSA_FLAG_MULTIPOINT_D_LEAF must be specified. The socket should then be bound to the specific interface on which the group is to be joined. Then WSAJoinLeaf() is invoked with the multicast address of the group to join. There are a couple of differences here. First, instead of binding to the wildcard address, you should bind to the specific local interface. Second, the outgoing (sending) interface does not have to be set. When the multicast group is joined, the outgoing interface is automatically set to the interface the socket is bound to. Finally, only a single multicast group can be joined on a socket. That is, unlike using setsockopt(), WSAJoinLeaf() can be invoked only once on a socket and the multicast group is joined until the socket is closed, there is no other way to leave the group.

The following program example demonstrates the IPv4/v6 multicasting using WSAJoinLeaf().

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), creating a new project

 

// Sample: IPv4/v6 Multicasting using WSAJoinLeaf()

//

// Files:

//      ip_wsajoinleaf.cpp    - this file

//      resolve.cpp     - common routines for name resolution

//      resolve.h       - header file for common routines

//

// Description:

//    This sample illustrates how to use the WSJoinLeaf API for

//    multicasting. This sample may be invoked as either a sender

//    or a receiver. This sample works for both IPv4 and IPv6.

//    The one drawback to using the WSAJoinLeaf API is that only

//    a single multicast group may be joined on a socket.

//

// Command Line:

//    ip_wsajoinleaf [-s] [-m str] [-p int] [-i str] [-b str] [-l] [-n int]

//       -i addr Local address to bind to

//       -j      Don't join group

//       -l 0/1  Disable/enable loopback

//       -m addr Multicast address to join

//       -n int  Send/recv count

//       -p int  Port number

//       -s      Act as sender; default is receiver

//       -t int  Set multicast TTL

//       -z int  Buffer size (in bytes)

//

// Link to ws2_32.lib

#include <winsock2.h>

#include <ws2tcpip.h>

#include "resolve.h"

#include <stdio.h>

 

#define MCASTADDRV4    "224.0.0.255"

#define MCASTADDRV6    "ff12::1"

#define MCASTPORT      "25000"

#define BUFSIZE        1024

#define DEFAULT_COUNT  500

#define DEFAULT_TTL    8

 

BOOL  bSender=FALSE,            // Act as as sender, default is receiver

      bLoopBack=FALSE,              // Enable or disable loopback

      bDontJoin=FALSE;                  // Join the group (sender only)

int   gSocketType=SOCK_DGRAM,    // datagram

      gProtocol=IPPROTO_UDP,            // UDP

      gCount=DEFAULT_COUNT,          // Number of messages to send/recv

      gBufferSize=BUFSIZE,                    // Buffer size for send/recv

      gLoopBack=0,                                  // Enable or disable loopback

      gTtl=DEFAULT_TTL;                       // Set multicast TTL

char *gInterface=NULL,                          // Local address to bind to

     *gMulticast=MCASTADDRV4,        // Multicast group to join

     *gPort=MCASTPORT;                      // Port number to use

 

// Function: usage

// Description: Display usage information.

int usage(char *progname)

{

    fprintf(stderr, "Usage: %s [-s] [-i local-addr] [-m remote-addr] [-p port-num] [-n count]\n", progname);

    fprintf(stderr,

                    "  -i addr Local address to bind to\n"

                    "  -l 0/1  Disable/enable loopback\n"

                    "  -m addr Multicast address to join\n"

                    "  -n int  Send/recv count\n"

                    "  -p int  Port number\n"

                    "  -s      Act as sender; default is receiver\n"

                    "  -t int  Set multicast TTL\n"

                    "  -z int  Buffer size (in bytes)\n"

                    );

    return 0;

}

 

// Function: ValidateArgs

// Description: Parse the command line and setup the global variables which indicate how this app should run.

void ValidateArgs(int argc, char **argv)

{

    int     i;

 

    for(i=1; i < argc ;i++)

    {

        if (((argv[i][0] != '/') && (argv[i][0] != '-')) || (strlen(argv[i]) < 2))

            usage(argv[0]);

        switch(tolower(argv[i][1]))

        {

            case 'i':               // local address to bind to

                if (i+1 >= argc)

                    usage(argv[0]);

                gInterface = argv[++i];

                break;

            case 'l':               // enable/disable loopback

                if (i+1 >= argc)

                    usage(argv[0]);

                bLoopBack = TRUE;

                gLoopBack = atoi(argv[++i]);

                break;

            case 'm':               // remote (multicast) address to connect/join to

                if (i+1 >= argc)

                    usage(argv[0]);

                gMulticast = argv[++i];

                break;

            case 'p':               // port number

                if (i+1 >= argc)

                    usage(argv[0]);

                gPort = argv[++i];

                break;

            case 'n':               // number of sends/recvs

                if (i+1 >= argc)

                    usage(argv[0]);

                gCount = atoi(argv[++i]);

                break;

            case 's':               // sender or receiver

                bSender = TRUE;

                break;

            case 't':               // multicast ttl

                if (i+1 >= argc)

                    usage(argv[0]);

                gTtl = atoi(argv[++i]);

                break;

            case 'z':               // buffer size

                if (i+1 >= argc)

                    usage(argv[0]);

                gBufferSize = atoi(argv[++i]);

                break;

            default:

                usage(argv[0]);

                break;

        }

    }

}

 

// Function: SetMulticastTtl

// Description: This routine sets the multicast TTL value for the socket.

int SetMulticastTtl(SOCKET s, int af, int ttl)

{

    char *optval=NULL;

    int   optlevel, option, optlen, rc;

 

    rc = NO_ERROR;

    if (af == AF_INET)

    {

        // Set the options for V4

        optlevel = IPPROTO_IP;

        option   = IP_MULTICAST_TTL;

        optval   = (char *) &ttl;

        optlen   = sizeof(ttl);

    }

    else if (af == AF_INET6)

    {

        // Set the options for V6

        optlevel = IPPROTO_IPV6;

        option   = IPV6_MULTICAST_HOPS;

        optval   = (char *) &ttl;

        optlen   = sizeof(ttl);

    }

    else

    {

        fprintf(stderr, "Attempting to set TTL for invalid address family!\n");

        rc = SOCKET_ERROR;

    }

 

    if (rc != SOCKET_ERROR)

    {

        // Set the TTL value

        rc = setsockopt( s, optlevel, option, optval, optlen);

        if (rc == SOCKET_ERROR)

        {

            fprintf(stderr, "SetMulticastTtl: setsockopt failed with error code %d\n", WSAGetLastError());

        }

        else

        {

            printf("Set multicast ttl to: %d\n", ttl);

        }

    }

    return rc;

}

 

// Function: SetMulticastLoopBack

// Description:

//    This function enabled or disables multicast loopback. If loopback is enabled

//    (and the socket is a member of the destination multicast group) then the

//    data will be placed in the receive queue for the socket such that if a

//    receive is posted on the socket its own data will be read. For this sample

//    it doesn't really matter as if invoked as the sender, no data is read.

int SetMulticastLoopBack(SOCKET s, int af, int loopval)

{

    char *optval=NULL;

    int   optlevel, option, optlen, rc;

 

    rc = NO_ERROR;

    if (af == AF_INET)

    {

        // Set the v4 options

        optlevel = IPPROTO_IP;

        option   = IP_MULTICAST_LOOP;

        optval   = (char *) &loopval;

        optlen   = sizeof(loopval);

    }

    else if (af == AF_INET6)

    {

        // Set the v6 options

        optlevel = IPPROTO_IPV6;

        option   = IPV6_MULTICAST_LOOP;

        optval   = (char *) &loopval;

        optlen   = sizeof(loopval);

    }

    else

    {

        fprintf(stderr, "Attempting to set multicast loopback for invalid address family!\n");

        rc = SOCKET_ERROR;

    }

    if (rc != SOCKET_ERROR)

    {

        // Set the multipoint loopback

        rc = setsockopt(s, optlevel, option, optval, optlen);

        if (rc == SOCKET_ERROR)

        {

            fprintf(stderr, "SetMulticastLoopBack: setsockopt failed with error code %d\n", WSAGetLastError());

        }

        else

        {

            printf("Setting multicast loopback to: %d\n", loopval);

        }

    }

    return rc;

}

 

// Function: SetSendInterface

// Description:

//    This routine sets the send (outgoing) interface of the socket.

//    Again, for v4 the IP address is used to specify the interface while for v6 its the scope-ID.

int SetSendInterface(SOCKET s, struct addrinfo *iface)

{

    char *optval=NULL;

    int   optlevel, option, optlen, rc;

 

    rc = NO_ERROR;

    if (iface->ai_family == AF_INET)

    {

        // Setup the v4 option values

        optlevel = IPPROTO_IP;

        option   = IP_MULTICAST_IF;

        optval   = (char *) &((SOCKADDR_IN *)iface->ai_addr)->sin_addr.s_addr;

        optlen   = sizeof(((SOCKADDR_IN *)iface->ai_addr)->sin_addr.s_addr);

    }

    else if (iface->ai_family == AF_INET6)

    {

        // Setup the v6 option values

        optlevel = IPPROTO_IPV6;

        option   = IPV6_MULTICAST_IF;

        optval   = (char *) &((SOCKADDR_IN6 *)iface->ai_addr)->sin6_scope_id;

        optlen   = sizeof(((SOCKADDR_IN6 *)iface->ai_addr)->sin6_scope_id);

    }

    else

    {

        fprintf(stderr, "Attempting to set sent interface for invalid address family!\n");

        rc = SOCKET_ERROR;

    }

    // Set send IF

    if (rc != SOCKET_ERROR)

    {

        // Set the send interface

        rc = setsockopt(s, optlevel, option, optval, optlen);

        if (rc == SOCKET_ERROR)

        {

            printf("setsockopt() failed with error code %d\n", WSAGetLastError());

        }

        else

        {

            printf("Set sending interface to: ");

            PrintAddress(iface->ai_addr, iface->ai_addrlen);

            printf("\n");

        }

    }

    return rc;

}

 

int main(int argc, char **argv)

{

    WSADATA             wsd;

    struct addrinfo    *reslocal = NULL, *resmulti = NULL;

    SOCKET              s, rs;

    char               *buf=NULL;

    int                 rc, i;

 

    if(argc < 2)

    {

        usage(argv[0]);

        exit(1);

    }

 

    ValidateArgs(argc, argv);

 

    // Load Winsock

    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)

    {

        printf("WSAStartup() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("WSAStartup() is OK!\n");

 

    // resolve the local interface first

    reslocal = ResolveAddress(gInterface, (bSender ? "0": gPort), AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP);

    if (reslocal == NULL)

    {

        fprintf(stderr, "Unable to resolve local interface: %s\n", gInterface);

        return -1;

    }

    else

        printf("ResolveAddress() should be fine!\n");

 

    // Create the socket - remember to specify the multicast flags

    s = WSASocket(

            reslocal->ai_family,

            reslocal->ai_socktype,

            reslocal->ai_protocol,

            NULL,

            0,

            WSA_FLAG_OVERLAPPED | WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF

            );

 

    if (s == INVALID_SOCKET)

    {

        fprintf(stderr, "socket(af = %d) failed with error code %d\n", reslocal->ai_family, WSAGetLastError());

        return -1;

    }

    else

        printf("socket(af = %d) is fine!\n", reslocal->ai_family);

 

    rc = bind(s, reslocal->ai_addr, reslocal->ai_addrlen);

    if (rc == SOCKET_ERROR)

    {

        fprintf(stderr, "bind() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

        printf("bind() is OK!\n");

 

    printf("bound to: ");

    PrintAddress(reslocal->ai_addr, reslocal->ai_addrlen);

    printf("\n");

 

    // Resolve the multicast address

    resmulti = ResolveAddress(gMulticast, gPort, reslocal->ai_family, reslocal->ai_socktype, reslocal->ai_protocol);

    if (resmulti == NULL)

    {

        fprintf(stderr, "Unable to resolve multicast address: %s\n", gMulticast);

        freeaddrinfo(reslocal);

        freeaddrinfo(resmulti);

        return -1;

    }

    else

        printf("ResolveAddress() is OK!\n");

 

    // Set the multicast TTL

    rc = SetMulticastTtl(s, resmulti->ai_family, gTtl);

    if (rc == SOCKET_ERROR)

    {

        freeaddrinfo(reslocal);

        freeaddrinfo(resmulti);

        return -1;

    }

 

    // Set the loopback value if indicated

    if (bLoopBack)

    {

        rc = SetMulticastLoopBack(s, resmulti->ai_family, gLoopBack);

        if (rc == SOCKET_ERROR)

        {

            freeaddrinfo(reslocal);

            freeaddrinfo(resmulti);

            return -1;

        }

    }

 

    // If the don't join option is set then just connect the socket

    if (bDontJoin == FALSE)

    {

        rs = WSAJoinLeaf(

                s,

                resmulti->ai_addr,

                resmulti->ai_addrlen,

                NULL,

                NULL,

                NULL,

                NULL,

                (bSender ? JL_SENDER_ONLY : JL_RECEIVER_ONLY)

                        );

        if (rs == INVALID_SOCKET)

        {

            fprintf(stderr, "WSAJoinLeaf() failed with error code %d\n", WSAGetLastError());

            freeaddrinfo(reslocal);

            freeaddrinfo(resmulti);

            return -1;

        }

        else

            printf("WSAJoinLeaf() is OK!\n");

    }

    else

    {

        rc = SetSendInterface(s, reslocal);

        if (rc == SOCKET_ERROR)

        {

            fprintf(stderr, "Unable to set outgoing multicast interface\n");

            freeaddrinfo(reslocal);

            freeaddrinfo(resmulti);

            return -1;

        }

 

        rc = connect(s, resmulti->ai_addr, resmulti->ai_addrlen);

        if (rc == SOCKET_ERROR)

        {

            fprintf(stderr, "connect() failed with error code %d\n", WSAGetLastError());

            freeaddrinfo(reslocal);

            freeaddrinfo(resmulti);

            return -1;

        }

        else

            printf("connect() is OK!\n");

    }

 

    printf("joining group: ");

    PrintAddress(resmulti->ai_addr, resmulti->ai_addrlen);

    printf("\n");

 

    freeaddrinfo(reslocal);

    freeaddrinfo(resmulti);

 

    buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, gBufferSize);

    if (buf == NULL)

    {

        fprintf(stderr, "HeapAlloc() for buffer failed with error code %d\n", GetLastError());

        return -1;

    }

    else

        printf("HeapAlloc() for buffer is OK!\n");

 

    memset(buf, '$', gBufferSize);

 

    if (bSender)

    {

        for(i=0; i < gCount ;i++)

        {

            rc = send(s, buf, gBufferSize, 0);

            if (rc == SOCKET_ERROR)

            {

                fprintf(stderr, "send() failed with error code %d\n", WSAGetLastError());

                HeapFree(GetProcessHeap(), 0, buf);

                return -1;

            }

            else

            {

                printf("wrote %d bytes\n", rc);

            }

        }

    }

    else

    {

        for(i=0; i < gCount ;i++)

        {

            rc = recv(s, buf, gBufferSize, 0);

            if (rc == SOCKET_ERROR)

            {

                fprintf(stderr, "recv() failed with error code %d\n", rc);

                HeapFree(GetProcessHeap(), 0, buf);

                return -1;

            }

            else

            {

                printf("read %d bytes\n", rc);

            }

        }

    }

 

    HeapFree(GetProcessHeap(), 0, buf);

    if(closesocket(s) == 0)

        printf("closesocket(s) is OK!\n");

    else

        printf("closesocket(s) failed with error code %d\n",WSAGetLastError());

 

    if(WSACleanup() == 0)

        printf("WSACleanup() is OK!\n");

    else

        printf("WSACleanup() failed with error code %d\n", WSAGetLastError());

    return 0;

}

 

Add (import) the existing resolve.h and its definition, resolve.cpp into the project. Firstly, copy both files from the previous project.

 

-----------------------------------------------------------

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), copying the header and its definition files.

 

Then paste those file into the current project file.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), Pasting the header and its definition files.

 

Then, add those files into the project using Add > Existing Item menu.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), Adding the header and its definition files to the existing project.

 

Multiple select those files and click the Add button.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), Selecting the header and its definition files.

 

Those files should be visible in the solution explorer as shown in the following Figure.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), The added header and its definition files seen in Solution explorer.

 

Build and run the project.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), running the program without any arguments

 

Run the project as receiver/client (in this case we run the receiver on 192.168.1.2).

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), running the program as receiver/client

 

Run the project as sender/server (in this case we run the sender on 192.168.1.1).

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), running the program as server/sender

 

The previous receiver/client screenshot is shown below.

 

Winsock and Multicasting: IPv4/v6 Multicasting using WSAJoinLeaf(), the receiver/client screenshot when communication was completed

 

 

 

Useful References:

 

1.      IPv4 Multicasting Tools and Settings.

2.      Windows Server 2003 Resource Kit Tools.

3.      An IP multicast may not be sent correctly from Windows 2000, Windows XP, or Windows Server 2003.

4.      TCP/IP and NBT configuration parameters for Windows XP.

 


< IPv4 & Multicast Sourcing | Multicasting Main | Reliable Multicasting >