TCP/IP network programming_ Chapter 14 multicast and broadcasting

14.1 multicast

The data transmission of multicast is based on UDP. Therefore, it is very close to the implementation of UDP server / client. The difference is that UDP data transmission is carried out with a single goal, and multicast data is delivered to a large number of hosts joining (registering) a specific group at the same time. In other words, when multicast is adopted, data can be delivered to multiple hosts at the same time

Advantages of data transmission mode and traffic of multicast

The data transmission characteristics of multicast can be integrated as follows

A multicast group is a class D IP address (224.0.0.0 ~ 239.255.255.255). Joining a multicast group can be understood as completing the following statement through a program:

Multicast is based on UDP, that is to say, the format of multicast packet is the same as that of UDP packet. It is only different from the general UDP packet. When a multicast packet is delivered to the network, the router will copy the packet and deliver it to multiple hosts. Like this, multicast needs to be completed with the aid of router, as shown in Figure 14-1


Figure 14-1 shows the process of transmitting multicast packets to AAA group to all hosts joining AAA group through router

I said at the beginning of this chapter:

Just look at figure 14-1. You may think that this is not conducive to network traffic, because routers frequently copy the same packet. But please consider it from another aspect

If a file is sent to 1000 hosts through TCP or UDP, it needs to be delivered 1000 times in total. Even if 10 hosts are combined into one network, so that 99% of the transmission paths are the same. But at this time, if the file is transmitted in multicast mode, it only needs to be sent once. At this time, the router in the network composed of 1000 hosts is responsible for copying the file and delivering it to the host. Because of this feature, Multicast is mainly used for "real time transmission of multimedia data"

In addition, although multicast communication can be achieved in theory, many routers do not support multicast, or even if they do, they deliberately block multicast due to network congestion. Therefore, in order to complete communication in routers that do not support multicast technology, There will also be tunneling technology (which is not a concern for multicast developers). We will only discuss programming methods in the context of supporting multicast services

Routing and TTL(Time to Live), and ways to join groups

Next, we discuss the programming methods related to multicast technology. In order to deliver multicast packets, TTL must be set. TTL is the abbreviation of Time to Live, which is the main factor determining the "packet delivery distance". TTL is expressed as an integer, and every time it passes through a router, it is reduced by 1. When TTL becomes 0, the packet can no longer be delivered, but can only be consumed. Therefore, The setting of TTL value is too large to affect the network traffic. Of course, if the setting is too small, it will not be able to pass to the target, which needs attention
Next, the TTL setting method is given. The TTL setting in the program is completed through the socket option in Chapter 9. The protocol layer related to setting TTL is IPPROTO_IP, option name is IP_ Therefore, TTL can be set to 64 with the following code
In addition, joining a multicast group is also done by setting socket options. The protocol layer related to joining a multicast group is IPPROTO_IP, option name is IP_ADD_MEMBERSHIP. You can join a multicast group with the following code
The above code only shows the part related to setsockopt function, and the details will be shown in the example later. Only IP is explained here_ MREP structure, which is defined as follows

Chapter 3: in_add struct, so only struct members are introduced. First, the first member IMR_ Write the IP address of the joined group in multiaddr. Second member imr_interface is the IP address of the host to which the socket to join the group belongs. Inaddr can also be used_ ANY.

Implementation of multicast Sender and Receiver

In multicast, "Sender" (hereinafter referred to as "Sender") and "Receiver" (hereinafter referred to as "Receiver") are used to replace the server and client. As the name implies, Sender here is the sending body of multicast data, and Receiver is the receiving body of data that needs to join the multicast group. The following discussion will give an example. The running scenario of this example is as follows

Next, the Sender code is given. The Sender is simpler than the Receiver because the Receiver needs to go through the process of joining the group, while the Sender only needs to create a UDP socket and send data to the multicast address

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define TTL 64
#define BUF_SIZE 30

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int send_sock;
    struct sockaddr_in mul_adr;
    int time_live = TTL;
    FILE *fp;
    char buf[BUF_SIZE];
    if (argc != 3)
    {
        printf("Usage : %s <GroupIP> <PORT> \n", argv[0]);
        exit(1);
    }

    send_sock = socket(PF_INET, SOCK_DGRAM, 0); /* Multicast data communication is done over UDP, so a UDP socket is created */
    memset(&mul_adr, 0, sizeof(mul_adr));
    mul_adr.sin_family = AF_INET; /* Set the destination address information of the transmission data. It is important to set the IP address to the multicast address */
    mul_adr.sin_addr.s_addr = inet_addr(argv[1]);
    mul_adr.sin_port = htons(atoi(argv[2]));

    /* Specify socket TTL information, which is a necessary procedure in Sender */
    setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
    if ((fp = fopen("news.txt", "r")) == NULL)
    {
       error_handling("fopen() error"); 
    }

    while (!feof(fp)) /* 38~42: In addition, the sleep function call in line 42 is mainly added to provide a certain time isolation for data transmission, which has no other special significance */
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
        sleep(2);
    }

    fclose(fp);
    close(send_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

From the above code, we can see that the Sender is not much different from the ordinary UDP socket program, but the multicast Receiver is somewhat different. In order to Receive the data to any address, it needs to go through the process of joining the multicast group. In addition, the Receive is also not much different from the UDP socket program. Next, the Receiver program used in combination with the above example is given

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int recv_sock;
    int str_len;
    char buf[BUF_SIZE];
    struct sockaddr_in adr;
    struct ip_mreq join_adr;
    if (argc != 3)
    {
        printf("Usage : %s <GroupIP> <POTR> \n", argv[0]);
        exit(1);
    }

    recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    adr.sin_port = htons(atoi(argv[2]));

    if (bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr)) == -1)
    {
        error_handling("bind() error");
    }

    /* 36 37: Initialize structure ip_mreg variable. Line xx initializes the multicast address and line xx initializes the IP address of the host to be added */
    join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]);
    join_adr.imr_interface.s_addr = htonl(INADDR_ANY);

    /* 40: Use socket option IP_ADD_MEMBERSHIP joins the multicast group. So far, all preparations for receiving the multicast group data specified in line xx have been completed */
    setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));

    while (1)
    {
        /* 45: Call the recvfrom function to receive the multicast data. If you do not need to know the host address information of the transmitted data, you can pass NULL and 0 to the fifth and sixth parameters of the recvfrom function respectively */
        str_len = recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
        if (str_len < 0)
        {
            break;
        }
        buf[str_len] = 0;
        fputs(buf, stdout);
    }

    close(recv_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

Operation result:




Have you ever run this example? The port numbers between Sender and Receiver should be consistent, although not mentioned, but they should be. The running order is not important, because unlike TCP socket, it does not send and Receive data in the connected state. Just because multicast belongs to the broadcast category, if you delay running Receive, you cannot Receive the previously transmitted multicast data

14.2 broadcasting

The broadcast described in this section is different from the multicast type in "sending data to multiple hosts at one time", but the transmission range is different. Multicast can receive data only by joining the multicast group even if it spans different networks. On the contrary, the broadcast can only transmit data to hosts in the same network

Understanding and implementation of broadcasting

Broadcast is a method of transmitting data to all hosts in the same network. Like multicast, broadcast is also based on UDP. According to the form of IP address used in data transmission, broadcast is divided into the following two types
The difference between them in code implementation mainly lies in the IP address. In the direct broadcast IP address, except for the network address, all the other host addresses are set to 1. For example, when you want to transmit data to all hosts in the network address 192.12.34, you can transmit data to 192.12.34.255. In other words, you can use the direct broadcast method to transmit data to all hosts in a specific area

On the contrary, the IP address used in the local broadcast is limited to 255.255.255.255. For example, when the host in the 192.32.24 network transfers data to 255.255.255.255, the data will be transferred to all hosts in the 192.32.24 network

So, how to implement Sender and Receiver? In fact, if you don't carefully observe the IP address used in the communication in the broadcast example, it's difficult to distinguish it from the UDP example. That is to say, the IP address used in the data communication is the only difference between the UDP example. The default generated set of characters will block the broadcast, so you only need to change the default settings through the following code
Call setsockopt function and set so_ The broadcast option is set to a value of 1 in the bcast variable. This means that data can be broadcast. Of course, the above socket option only needs to be changed in Sends, which is not required for the implementation of Receiver

Implement Sender and Receiver of broadcast data

In order to compare with the multicast example, the previous news_snder.c and news_receiver.c is an example of broadcasting

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int send_sock;
    struct sockaddr_in broad_adr;
    FILE *fp;
    char buf[BUF_SIZE];
    int so_brd = 1;
    if (argc != 3)
    {
        printf("Usage : %s <Boradcast IP> <PORT> \n", argv[0]);
        exit(1);
    }

    send_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&broad_adr, 0, sizeof(broad_adr));
    broad_adr.sin_family = AF_INET;
    broad_adr.sin_addr.s_addr = inet_addr(argv[1]);
    broad_adr.sin_port = htons(atoi(argv[2]));

    setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, (void*)&so_brd, sizeof(so_brd));
    if ((fp = fopen("news.txt", "r")) == NULL)
    {
        error_handling("fopen() error");
    }

    while (!feof(fp))
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
        sleep(2);
    }

    close(send_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

Line 31 changes the optional UDP socket created in line 25 to enable it to send broadcast data. The rest is the same as UDP Sender. Next, the broadcast Receiver is given

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int recv_sock;
    struct sockaddr_in adr;
    int str_len;
    char buf[BUF_SIZE];
    if (argc != 2)
    {
        printf("Usage : %s <PORT> \n", argv[0]);
        exit(1);
    }

    recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
    memset(&adr, 0, sizeof(adr));
    adr.sin_family = AF_INET;
    adr.sin_addr.s_addr = htonl(INADDR_ANY);
    adr.sin_port = htons(atoi(argv[1]));

    if (bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr)) == -1)
    {
        error_handling("bind() error");
    }

    while (1)
    {
        str_len = recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
        if (str_len < 0)
        {
            break;
        }

        buf[str_len] = 0;
        fputs(buf, stdout);
    }

    close(recv_sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

Operation result:


Conclusion:

You can download this book from the following website
https://www.jiumodiary.com/

Time: June 6, 2020

Tags: socket network Programming REST

Posted on Fri, 05 Jun 2020 23:00:15 -0400 by ashwood