网络编程多播——Multicast

IP多播(也称多址广播或组播)技术,是一种允许一台或多台主机(多播源)发送单一数据包到多台主机(一次的,同时的)的TCP/IP网络技术。

通俗点讲,多播也称组播,大概可以理解为分组广播的意思,是介于单播和广播之间的一种通信机制,使用多播方式,可以实现对局域网内一组特定的主机进行通信,对局域网节点分组,加入该分组即可接收该分组的消息,而未加入分组则收不到消息。

多播编程步骤

1. 建立套接字接口  
2. 设置套接字属性
3. 加入特定的多播组
4. 发送/接收信息
5. 离开多播组
6. 关闭套接字
* 若只是发信息,可不用加入组,直接向该组发送信息即可

多播相关套接字选项

1.  IP_MULTICASE_TTL
    设置超时时间, 范围是0~255
2.  IP_MULTICAST_IF
    指定使用的网络接口,如果主机有多个网络接口,不设置该选项则使用默认接口发送接收,使用该选项可指定某特定网络接口发送和接收信息
3. IP_MULTICAST_LOOP
    设置是否晕熏数据发送到本地loop地址
4. IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP
    加入/离开特定的多播组, 操作一个struct ip_mreq结构体,里面包含带加入/离开组的信息

多播编程客户端示例:

(只发送)

#define MULT_ADDR "224.0.0.250"
#define MULT_PORT 9999
#define MSG "multicast message"
int main()
{
    int sock;
    struct sockaddr_in mult_addr;
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        return -1;
    }

    memset(&mult_addr, 0, sizeof(mult_addr));
    mult_addr.sin_family = AF_INET;
    mult_addr.sin_port = htons(MULT_PORT);
    mult_addr.sin_addr.s_addr = inet_addr(MULT_ADDR);

    socklen_t l = sizeof(mult_addr);
    unsigned char ttl = 20;
    l = sizeof(ttl);
    setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, l);
    l = sizeof(mult_addr);

    while (1) {
        sendto(sock, MSG, sizeof(MSG), 0, (struct sockaddr *)&mult_addr, l);
        printf("SEND to : %s buf: %s\n", inet_ntoa(mult_addr.sin_addr), MSG);

        if (getchar() == 'q') {
            break;
        }
    }

    close(sock);
    return 0;
}

多播编程服务端示例:

(只接收)

#define MULT_ADDR "224.0.0.250"
#define MULT_PORT 9999
int main()
{
    struct sockaddr_in addr;
    int sock;
    struct ip_mreq mreq;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        printf("failed to create udp socket\n");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(MULT_PORT);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
        printf("failed to bind socket\n");
        close(sock);
        return -1;
    }

    memset(&mreq, 0, sizeof(mreq));
    mreq.imr_multiaddr.s_addr = inet_addr(MULT_ADDR);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);

    char buf[64];
    socklen_t l = sizeof(addr);
    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        printf("failed to join multicast group\n");
        close(sock);
        return -1;
    }
    while (1) {
        int n = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &l);
        if (n > 0) {
            printf("RECIVE from %s => buf: %s\n", inet_ntoa(addr.sin_addr), buf);
        }
    }

    setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
    close(sock);
    return 0;
}

SOURCE CODE