《TCP/IP网络编程》学习笔记 | Chapter 14:多播与广播

《TCP/IP网络编程》学习笔记 | Chapter 14:多播与广播

多播

多播(Multicast)方式的数据传输是基于UDP完成的,可以同时向多个主机传递数据。

多播常用于视频会议、在线直播、IPTV等场景,其中数据需要发送给多个特定的接收者而不是所有人。

多播的数据传输方式和特点

多播的特点:

  1. 多播服务器针对特定的多播组,只发送一次数据。
  2. 即使只发送一次数据,该组内所有客户端都会接受到数据。
  3. 多播组数可以在IP地址范围内任意增加。
  4. 加入多播组就能收到发往该多播组的数据。

多播组时D类IP地址,即224.0.0.0~239.255.255.255,并被划分为三类:

  • 局部链接多播地址:224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包。
  • 预留多播地址:224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议。
  • 管理权限多播地址:239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。

「加入多播组」可以理解为通过程序完成如下声明:在 D 类IP地址中,我希望接收发往目标 239.234.218.234 的多播数据。

多播技术基于UDP传输,向网络传输1个多播数据包时,路由器会复制该数据包并传递到多个主机,如下图所示:

在这里插入图片描述

多播的传输需要借助路由器完成。若通过 TCP 或 UDP 向 1000 个主机发送文件,则共需要传递 1000 次。但是此时如果用多播网络传输文件,则只需要发送一次。正是由于这样的特性,大大节省了网络流量,减少了占用带宽,同时也减少了发送端的重复无用的工作,多播主要用于“多媒体数据的实时传输”。

要实现多播通信,要求介于多播源和接收者之间的路由器、集线器、交换机以及主机均需支持IP多播。目前,IP多播技术已得到硬件、软件厂商的广泛支持。

然而,有些路由器并不支持多播,或即便支持也因网络拥堵问题故意阻断多播。因此,为了在不支持多播的路由器中完成多播通信,也会使用隧道(Tunneling)技术。

路由(Routing)和 TTL(Time to Live,生存时间),以及加入组的办法

为了传递多播数据包,必须设置 TTL ,它是决定「数据包传递距离」的主要因素。TTL 用整数表示,并且每经过一个路由器就减一。TTL 变为 0 时,该数据包就无法再被传递,只能销毁。因此,TTL 的值设置过大将影响网络流量。当然,设置过小,也无法传递到目标。

在这里插入图片描述

缺省情况下,发送 IP 多播数据报时其 TTL 值为 1。与设置 TTL 相关的协议层为 IPPROTO_IP ,选项名为 IP_MULTICAST_TTL。这些阈值将针对具有以下初始 TTL 值的多播数据报强制实施相应约定:

  • 0:限定在同一主机
  • 1:限定在同一子网
  • 32:限定在同一站点
  • 64:限定在同一地区
  • 128:限定在同一洲
  • 255:范围不受限制

站点和地区并未严格定义,站点可以根据实际情况再分为更小的管理单元。

因此,可以用如下代码把 TTL 设置为 64:

int send_sock;
int time_live = 64;
...
send_sock = socket(PF_INET, SOCK_DGRAM, 0);
setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&time_live, sizeof(time_live));
...

加入多播组也通过设置套接字可选项来完成。加入多播组相关的协议层为 IPPROTO_IP,选项名为 IP_ADD_MEMBERSHIP 。可通过如下代码加入多播组:

int recv_sock;
struct ip_mreq join_adr;
...
recv_sock = socket(PF_INET, SOCK_DGRAM, 0);
...
join_adr.imr_multiaddr.s_addr = "多播组地址信息";
join_adr.imr_interface.s_addr = "加入多播组的主机地址信息";
setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));
...

下面是 ip_mreq 结构体的定义:

struct ip_mreq
{
    struct in_addr imr_multiaddr; // 写入加入组的IP地址
    struct in_addr imr_interface; // 加入该组的套接字所属主机的IP地址
};

有关多播的实现需要设置UDP套接字的一些可选项,以表格的形式进行汇总:

IPPROTO_IP 选项名说明数据类型
IP_MULTICAST_TTL生存时间(Time To Live),组播传送距离int
IP_ADD_MEMBERSHIP加入组播struct ip_mreq
IP_DROP_MEMBERSHIP离开组播struct ip_mreq
IP_MULTICAST_IF获取默认接口或设置接口int
IP_MULTICAST_LOOP组播数据回送,缺省默认回送int

实现多播 Sender 和 Receiver

多播中用「发送者」(以下称为 Sender) 和「接收者」(以下称为 Receiver)替代服务器端和客户端。顾名思义,此处的 Sender 是多播数据的发送主体,Receiver 是需要多播组加入过程的数据接收主体。下面是示例,示例的运行场景如下:

  • Sender : 向 AAA 组广播(Broadcasting)文件中保存的新闻信息
  • Receiver : 接收传递到 AAA 组的新闻信息。

news_sender.c 程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.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); // 创建  UDP 套接字
    memset(&mul_adr, 0, sizeof(mul_adr));
    mul_adr.sin_family = AF_INET;
    mul_adr.sin_addr.s_addr = inet_addr(argv[1]); // 必须将IP地址设置为多播地址
    mul_adr.sin_port = htons(atoi(argv[2]));
    // 指定套接字中 TTL 的信息
    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)) // 如果文件没结束就返回0
    {
        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);
}

news_receiver.c 程序:

#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;
    int str_len;
    char buf[BUF_SIZE];
    struct sockaddr_in adr;
    struct ip_mreq join_adr;
    if (argc != 3)
    {
        printf("Usage : %s <GroupIP> <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[2]));

    if (bind(recv_sock, (struct sockaddr *)&adr, sizeof(adr)) == -1)
        error_handling("bind() error");
    // 初始化结构体
    join_adr.imr_multiaddr.s_addr = inet_addr(argv[1]); // 多播组地址
    join_adr.imr_interface.s_addr = htonl(INADDR_ANY);  // 待加入的IP地址
    // 利用套接字选项 IP_ADD_MEMBERSHIP 加入多播组,完成了接受指定的多播组数据的所有准备
    setsockopt(recv_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&join_adr, sizeof(join_adr));

    while (1)
    {
        // 通过 recvfrom 函数接受多播数据。如果不需要知道传输数据的主机地址信息,可以向recvfrom函数的第5 6参数分贝传入 NULL 0
        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);
}

通过结果可以看出,使用 sender 多播信息,通过 receiver 接收广播,如果延迟运行 receiver 将无法接受之前发送的信息。

广播

广播(Broadcast)在「一次性向多个主机发送数据」这一点上与多播类似,但传输数据的范围有区别。多播即使在跨越不同网络的情况下,只要加入多播组就能接受数据。相反,广播只能向同一网络中的主机传输数据。

广播的理解和实现方法

广播是向同一网络中的所有主机传输数据的方法。与多播相同,广播也是通过 UDP 来完成的。根据传输数据时使用的IP地址形式,广播分为以下两种:

  • 直接广播(Directed Broadcast):向特定区域内的所有主机传输数据。广播的IP地址除了网络地址外,其余主机地址全部设置为1,例如希望向 192.168.1.32 所在网络中的所有主机发送广播数据时可以向 192.168.1.255 传输。
  • 本地广播(Local Broadcast):本地广播的IP地址限定为 255.255.255.255,向该主机所在网络的所有主机发送广播数据。例如,192.32.24 网络中的主机向 255.255.255.255 传输数据时,数据将传输到 192.32.24 网络中所有主机。

有关广播的实现需要设置UDP套接字的一些可选项:

SOL_SOCKET 选项名说明数据类型
SO_BROADCAST允许或禁止发送广播数据(1启用,0不启用)int

数据通信中使用的IP地址是与 UDP 示例的唯一区别。默认生成的套接字会阻止广播,因此,只需通过如下代码更改默认设置:

int send_sock;
send_sock = socket(AF_INET, SOCK_DGRAM, 0); // 使用UDP传输

int opt = 1; // 启用广播
setsockopt(send_sock, SOL_SOCKET, SOL_SOCKET, (void *)&opt, sizeof(opt));

实现广播数据的 Sender 和 Receiver

news_sender_brd.c 程序:

#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 <GroupIP> <PORT>\n", argv[0]);
        exit(1);
    }
    send_sock = socket(PF_INET, SOCK_DGRAM, 0); // 创建  UDP 套接字
    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)) // 如果文件没结束就返回0
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(send_sock, buf, strlen(buf), 0, (struct sockaddr *)&broad_adr, sizeof(broad_adr));
        sleep(2);
    }
    fclose(fp);
    close(send_sock);
    return 0;
}

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

news_receiver_brd.c 程序:

#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;
    int str_len;
    char buf[BUF_SIZE];
    struct sockaddr_in adr;
    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)
    {
        // 通过 recvfrom 函数接受数据。如果不需要知道传输数据的主机地址信息,可以向recvfrom函数的第5 6参数分贝传入 NULL 0
        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);
}

基于 Windows 的实现

在Windows平台中,该技术的套接字设置没有区别,只需要修改对应的变量和头文件即可。

基于 Windows 的多播示例程序

news_sender_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define TTL 64
#define BUF_SIZE 30

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

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET sendSock;
    SOCKADDR_IN mulAddr;
    int timeLive = TTL;
    char buf[BUF_SIZE];

    if (argc != 3)
    {
        printf("Usage: %s <GroupIP> <port>\n", argv[0]);
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    sendSock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sendSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    memset(&mulAddr, 0, sizeof(mulAddr));
    mulAddr.sin_family = AF_INET;
    mulAddr.sin_addr.s_addr = inet_addr(argv[1]);
    mulAddr.sin_port = htons(atoi(argv[2]));

    setsockopt(sendSock, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&timeLive, sizeof(timeLive));

    FILE *fp = fopen("news.txt", "r");
    if (fp == NULL)
        ErrorHanding("fopen() error!");

    while (!feof(fp))
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(sendSock, buf, strlen(buf), 0, (SOCKADDR *)&mulAddr, sizeof(mulAddr));
        Sleep(2000);
    }

    closesocket(sendSock);
    WSACleanup();

    return 0;
}

news_receiver_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define BUF_SIZE 30

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

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET recvSock;
    SOCKADDR_IN recvAddr;
    struct ip_mreq joinAddr;
    int strLen;
    char buf[BUF_SIZE];

    if (argc != 3)
    {
        printf("Usage: %s <GroupIP> <port>\n", argv[0]);
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    recvSock = socket(PF_INET, SOCK_DGRAM, 0);
    if (recvSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    memset(&recvAddr, 0, sizeof(recvAddr));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvAddr.sin_port = htons(atoi(argv[2]));

    if (bind(recvSock, (SOCKADDR *)&recvAddr, sizeof(recvAddr)) == SOCKET_ERROR)
        ErrorHanding("bind() error!");

    joinAddr.imr_multiaddr.s_addr = inet_addr(argv[1]);
    joinAddr.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(recvSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&joinAddr, sizeof(joinAddr)) == SOCKET_ERROR)
        ErrorHanding("setsocket() error!");

    while (1)
    {
        strLen = recvfrom(recvSock, buf, BUF_SIZE - 1, 0, NULL, 0);
        if (strLen < 0)
            break;
        buf[strLen] = '\0';
        fputs(buf, stdout);
    }

    closesocket(recvSock);
    WSACleanup();

    return 0;
}

编译:

gcc news_sender_win.c -lwsock32 -o newsSendWin
gcc news_receiver_win.c -lwsock32 -o newsRecvWin

运行结果:

// 接收端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsRecvWin 224.1.1.2 9190
A powerful magnitude-7.7 earthquake struck central Myanmar on Friday, causing widespread devastation. The confirmed death toll from the earthquake has risen to 1,644.
// 发送端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsSendWin 224.1.1.2 9190

基于 Windows 的本地广播示例程序

news_sender_local_broad_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define BUF_SIZE 30

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

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET sendSock;
    SOCKADDR_IN localBroadAddr;
    int brd = 1;
    char buf[BUF_SIZE];

    if (argc != 3)
    {
        printf("Usage: %s <GroupIP> <port>\n", argv[0]);
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    sendSock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sendSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    memset(&localBroadAddr, 0, sizeof(localBroadAddr));
    localBroadAddr.sin_family = AF_INET;
    localBroadAddr.sin_addr.s_addr = inet_addr(argv[1]);
    localBroadAddr.sin_port = htons(atoi(argv[2]));

    // 广播
    setsockopt(sendSock, SOL_SOCKET, SO_BROADCAST, (void *)&brd, sizeof(brd));

    FILE *fp = fopen("news.txt", "r");
    if (fp == NULL)
        ErrorHanding("fopen() error!");

    while (!feof(fp))
    {
        fgets(buf, BUF_SIZE, fp);
        sendto(sendSock, buf, strlen(buf), 0, (SOCKADDR *)&localBroadAddr, sizeof(localBroadAddr));
        Sleep(2000);
    }

    closesocket(sendSock);
    WSACleanup();

    return 0;
}

news_receiver_local_broad_win.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define BUF_SIZE 30

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

int main(int argc, char *argv[])
{
    WSADATA wsaData;
    SOCKET recvSock;
    SOCKADDR_IN recvAddr;
    int strLen;
    char buf[BUF_SIZE];

    if (argc != 2)
    {
        printf("Usage: %s <port>\n", argv[0]);
        exit(1);
    }

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        ErrorHanding("WSAStartup() error!");

    recvSock = socket(PF_INET, SOCK_DGRAM, 0);
    if (recvSock == INVALID_SOCKET)
        ErrorHanding("socket() error!");

    memset(&recvAddr, 0, sizeof(recvAddr));
    recvAddr.sin_family = AF_INET;
    recvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    recvAddr.sin_port = htons(atoi(argv[1]));

    if (bind(recvSock, (SOCKADDR *)&recvAddr, sizeof(recvAddr)) == SOCKET_ERROR)
        ErrorHanding("bind() error!");

    while (1)
    {
        strLen = recvfrom(recvSock, buf, BUF_SIZE - 1, 0, NULL, 0);
        if (strLen < 0)
            break;
        buf[strLen] = '\0';
        fputs(buf, stdout);
    }

    closesocket(recvSock);
    WSACleanup();

    return 0;
}

编译:

gcc news_sender_local_broad_win.c -lwsock32 -o newsSendLocalBroadWin
gcc news_receiver_local_broad_win.c -lwsock32 -o newsRecvLocalBroadWin

运行结果:

// 接收端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsRecvLocalBroadWin 9190
A powerful magnitude-7.7 earthquake struck central Myanmar on Friday, causing widespread devastation. The confirmed death toll from the earthquake has risen to 1,644.
// 发送端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsSendLocalBroadWin 255.255.255.255 9190

基于 Windows 的直接广播示例程序

前一小节的程序不用变,我们将本地广播地址改成自己主机的地址。

按下 win + R,输入 cmd,进入,输入 ipconfig 指令,就能找到自己主机的 IPv4 地址。

在这里插入图片描述

再次运行程序,修改发送端指定的发送 IP 地址为我们主机的地址。

运行结果:

// 接收端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsRecvLocalBroadWin 9190
A powerful magnitude-7.7 earthquake struck central Myanmar on Friday, causing widespread devastation. The confirmed death toll from the earthquake has risen to 1,644.
// 发送端
C:\Users\81228\Documents\Program\TCP IP Project\Chapter 14>newsSendLocalBroadWin 192.168.113.1 9190

多播 VS 广播

对比

  • 接收者范围: 广播发送给所有设备,而多播只发送给特定的组。
  • 网络效率: 多播比广播更高效,因为它减少了不必要的数据传输。
  • 地址类型: 广播使用广播地址,多播使用多播地址。
  • 适用场景: 广播适用于需要通知所有设备的场景,而多播适用于需要向特定群体发送数据的场景。

多播的使用场景

  1. 大规模数据分发: 股票市场信息、新闻更新或在线直播。
  2. 视频会议和在线教育
  3. IPTV和多媒体流
  4. 网络监控和安全
  5. 分布式计算
  6. 实时数据服务: 天气更新、交通信息或金融市场数据,可以多播给所有订阅服务的用户。

广播的使用场景

  1. 局域网内通信: 如打印作业请求或网络发现协议。
  2. 设备发现: 一些设备和服务使用广播来发现网络上的其他设备。
  3. 游戏和娱乐: 在局域网游戏或多媒体应用中,广播可以用于快速发现和连接游戏服务器或媒体播放设备。
  4. 紧急通知系统: 在某些情况下,可能需要向局域网内的所有设备发送紧急通知或警报。

习题

(1)TTL的含义是什么?请从路由器的角度说明较大的TTL值与较小的TTL值之间的区别及问题。

TTL是Time to Live的简写,意思是生存时间,是决定“数据包传递距离”的主要因素。

TTL的值设置过大将影响网络流量。当然,设置过小,也无法传递到目标。

(2)多播与广播的异同点是什么?请从数据通信的角度说明。

广播在“一次性向多个主机发送数据”这一点上与多播类似,但传输数据的范围有区别,多播即使在跨越不同网络的情况下,只要加入多播组就能接收数据,相反,广播只能向同一网络中的主机传输数据。

(3)下列关于多播的描述错误的是?

a. 多播是用来向加入多播组的所有主机传输数据的协议。
b. 主机连接到同一网络才能加入多播组,也就是说,多播组无法跨越多个网络。
c. 能够加入多播组的主机数并无限制,但只能有1个主机(Sender)向该组发送数据。
d. 多播时使用的套接字是UDP套接字,因为多播是基于UDP进行数据通信的。

答:b、c。

(4)多播也对网络流量有利,请比较TCP数据交换方式解释其原因。

若通过TCP向1000个主机发送文件,共需传递1000次,但此时若使用多播方式传输文件,则是需要发送1次,之后由路由器进行转发。

(5)多播方式的数据通信需要MBone虚拟网络。换言之, MBone是用于多播网络,但它是虚拟网络。请解释此处的“虚拟网络”。

“虚拟网络”是指一个不依赖于实际物理网络硬件的网络拓扑,它通过在现有物理网络上叠加逻辑结构和功能来实现特定目的。在多播通信中,MBone(Multicast Backbone)作为虚拟网络,起到了支持多播数据传输的作用。

具体来说,MBone的“虚拟网络”特性包含以下几点:

  1. 建立在现有的物理网络之上:
    MBone并不是一个独立的物理网络,而是通过软件配置和协议(如多播路由协议)在现有的IP网络(如互联网)中创建的逻辑网络。

  2. 逻辑拓扑:
    MBone使用一组支持多播的路由器(通常通过多播路由协议如 DVMRP 或 PIM)来构建虚拟链路。数据在这些逻辑链路之间传递,而不必依赖物理链路的具体布局。

  3. 多播组成员动态加入和离开:
    通过MBone,用户可以动态加入或离开一个多播组,这种灵活性由虚拟网络的逻辑实现,而不是由物理硬件决定。

  4. 支持多播流量的转发和优化:
    多播通常需要将一份数据高效地分发到多个目的地。MBone的虚拟网络通过在逻辑层次管理数据包的转发,避免了在物理网络中传输过多的冗余数据。

总结:MBone被称为虚拟网络,是因为它依赖现有的物理网络,通过软件和协议来构建支持多播通信的逻辑网络。它为多播通信提供了必要的基础设施,而无需物理网络的重新部署或重大改造。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值