Question: Is there any other way of sending one-to-many data with UDP?

Multicast in UDP communication

Multicast is 向特定组中的所有主机传输数据的方法 , multicast is also called multicast
Features of multicast data transmission:
  • The multicast sender only sends data once for a specific multicast group, and all hosts in the group can receive the data
  • A host joins a specific group to receive multicast data in that group
  • Multicast groups can be added arbitrarily within the IP address range

Key question: how to send and receive multicast data

A multicast group is a D class address (224.0.0.0 - 239.255.255.255)
"Joining a multicast group" can be understood as an application made by a UDP network program
  • For example: apply to receive multicast data sent to 239.234.111.222
  • ie: set properties ( IPPROTO_IP, IP_ADD_MEMBERSHP )
The way to send multicast data is the same as the way to send normal UDP data
  • Preliminary operation: set properties, such as: ( IPPROTO_IP, IP_MULTICAST_TTL )

Precautions

Hosts joining the same multicast group are not necessarily in the same network. Therefore, the maximum forwarding times (TTL) of multicast data must be set
  • TTL (ie: Time To Live) is the main factor that determines the distance of data transmission
  • TTL is expressed as an integer and is decremented by 1 for every route passed
  • When the TTL becomes 0, the data cannot continue to be transmitted and can only be destroyed

Multicast Programming: Sending Side

IP_MULTCAST_TTL: used to set the "maximum transmission distance" of multicast data, default 1
IP_MULTICAST_IF: Used to set the network interface (network card) from which multicast data is sent, default: 0.0.0.0
 默认 0.0.0.0 情况下操作系统会自主选择使用哪个网络接口,但在[多网卡主机]的[实际工程应用]中,最好手工指定!!
IP_MULTCAST_LOOP: Used to set whether multicast data is sent back to this machine, the default is 1 (1, sent back to this machine)
 remote.sin_family = AF_INET;
remote.sin_addr.s_addr = inet_addr("224.1.1.168");
remote.sin_port = htons(8888);

setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));

do {
    len = sizeof(remote);
    r = sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&remote, len);
    sleep(1);
}while(r > 0);

Multicast Programming: Receiver

IP_ADD_MEMBRESHIP: used to apply to join a multicast group, the parameters are: multicast group and local address
 struct ip_mreq {
    // group address
    struct in_addr inmr_multiaddr;
    // local host address
    struct in_addr imr_interface
}

👇

 struct ip_mreq group = {0};

group.imr_multiaddr.s_addr = inet_addr("224.1.1.168");
group.imr_interface.s_addr = htonl(INADDR_ANY);  // 监听所有网卡

setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

do {
    len = sizeof(remote);
    r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
    buf[r] = 0;
    printf("r = %d\n", r);
    printf("msg = %s\n", buf);
}while (r > 0)

Exit the multicast group

quit = setsockopt(sock, IP_PROTO_IP, IP_DROP_MEMBERSHIP, &group, sizeof(group));

 if (quit == 0) {
    break;
}

Programming Experiment: UDP Multicast Programming

mul_tx.c
 #include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int sock = 0;
    struct sockaddr_in remote = {0};
    socklen_t len = 0;
    char buf[128] = "D.T.Software";
    struct in_addr addr = {0};

    int ttl = 0;
    int loop = 0;

    sock = socket(PF_INET, SOCK_DGRAM, 0);

    if (sock == -1) {
        printf("socket error\n");
        return -1;
    }

    remote.sin_family = AF_INET;
    remote.sin_addr.s_addr = inet_addr("224.1.1.168");
    remote.sin_port = htons(8888);

    //-------------------------
    ttl = 0;
    len = sizeof(ttl);
    getsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, &len);  // 可以不设置,ttl 默认为 1 
    printf("default ttl = %d\n", ttl);

    ttl = 32;
    len = sizeof(ttl);
    setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, len); 
    printf("current ttl = %d\n", ttl);

    loop = 0;
    len = sizeof(loop);
    getsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &len);    // 可以不设置,ttl 默认为 1 ,即本机也会收到
    printf("default loop = %d\n", loop);

    // addr.s_addr = inet_addr("192.168.3.221");  // 具体指定使用哪一块网卡进行数据广播
    addr.s_addr = htonl(INADDR_ANY);              // 交由操作系统进行选择
    len = sizeof(addr);
    setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &addr, len);    // 可以不设置,默认为 INADDR_ANY 即 "0.0.0.0", 交由操作系统选择使用哪个网卡
    printf("current if = %s\n", inet_ntoa(addr));                // 当主机有多个网卡,在实际工程使用时,最好手工指定使用那块网卡广播数据
    //-------------------------

    while (1) {
        len = sizeof(remote);

        sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&remote, len);

        sleep(1);
    }

    close(sock);

    return 0;
}
mul_rx.c
 #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    int server = 0;
    struct sockaddr_in saddr = {0};
    struct sockaddr_in remote = {0};
    struct ip_mreq group = {0};
    int len = 0;
    char buf[32] = {0};
    int r = 0;

    server = socket(PF_INET, SOCK_DGRAM, 0);

    if (server == -1) {
        printf("server socket error");
        return -1;
    }

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(8888);

    if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
        printf("udp server bind error\n");
        return -1;
    }

    printf("udp server start sucess\n");

    group.imr_multiaddr.s_addr = inet_addr("224.1.1.168");
    group.imr_interface.s_addr = htonl(INADDR_ANY);

    setsockopt(server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));

    while (1) {
        len = sizeof(remote);

        r = recvfrom(server, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);

        if (r > 0) {
            buf[r] = 0;

            printf("Recvive: %s\n", buf);
        } else {
            break;
        }
    }

    close(server);

    return 0;
}

summary

Unicast: one-to-one data transmission, that is: specify the target host to send data
Broadcast (must be the same LAN)
  • Local broadcast: Local LAN broadcasts data, all hosts can receive data
  • Direct broadcast: The specified network broadcasts data, and all hosts in the target network can receive the data
Multicast (multicast) (can be different from a local area network)
  • Send data to the specified multicast address, and all hosts "subscribed" to this address can receive the data

TianSong
737 声望139 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧