第十四章(多播与广播)学习笔记

2019-11-18

22:12:21

参考:https://github.com/riba2534/TCP-IP-NetworkNote/tree/master/ch14

 

 

 

 

14.1.1 多播的数据传输方式以及流量方面的优点

多播的数据传输特点可整理如下:

  • 多播服务器端针对特定多播组,只发送 1 次数据。
  • 即使只发送 1 次数据,但该组内的所有客户端都会接收数据
  • 多播组数可以在 IP 地址范围内任意增加

多播组是 D 类IP地址(224.0.0.0~239.255.255.255),「加入多播组」可以理解为通过程序完成如下声明:

在 D 类IP地址中,我希望接收发往目标 239.234.218.234 的多播数据

多播是基于 UDP 完成的,也就是说,多播数据包的格式与 UDP 数据包相同。只是与一般的 UDP 数据包不同。向网络传递 1 个多播数据包时,路由器将复制该数据包并传递到多个主机。像这样,多播需要借助路由器完成。如图所示:

若通过 TCP 或 UDP 向 1000 个主机发送文件,则共需要传递 1000 次。但是此时如果用多播网络传输文件,则只需要发送一次。这时由 1000 台主机构成的网络中的路由器负责复制文件并传递到主机。就因为这种特性,多播主要用于「多媒体数据实时传输」。

另外,理论上可以完成多播通信,但是不少路由器并不支持多播,或即便支持也因网络拥堵问题故意阻断多播。因此,为了在不支持多播的路由器中完成多播通信,也会使用隧道(Tunneling)技术。

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

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

接下来是 TTL 的设置方法。TTL 是可以通过第九章的套接字可选项完成的。与设置 TTL 相关的协议层为 IPPROTO_IP ,选项名为 IP_MULTICAST_TTL。因此,可以用如下代码把 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(time_live);
...

下面是 ip_mreq 结构体的定义

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

14.1.3 实现多播 Sender 和 Receiver

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

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

下面是两个代码:

 

 news_sender.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define TTL 64
 9 #define BUF_SIZE 30
10 void error_handling(char *message);
11 
12 int main(int argc, char *argv[])
13 {
14     int send_sock;
15     struct sockaddr_in mul_adr;
16     int time_live=TTL;
17     FILE *fp;
18     char buf[BUF_SIZE];
19 
20     if(argc!=3){
21         printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);
22         exit(1);
23     }
24       
25     send_sock=socket(PF_INET, SOCK_DGRAM, 0);
26     memset(&mul_adr, 0, sizeof(mul_adr));
27     mul_adr.sin_family=AF_INET;
28     mul_adr.sin_addr.s_addr=inet_addr(argv[1]);  // Multicast IP
29     mul_adr.sin_port=htons(atoi(argv[2]));       // Multicast Port
30     
31     setsockopt(send_sock, IPPROTO_IP, 
32         IP_MULTICAST_TTL, (void*)&time_live, sizeof(time_live));
33     
34     if((fp=fopen("news.txt", "r"))==NULL)
35         error_handling("fopen() error");
36 
37     while(!feof(fp))   /* Broadcasting */
38     {
39         fgets(buf, BUF_SIZE, fp);
40         sendto(send_sock, buf, strlen(buf), 
41             0, (struct sockaddr*)&mul_adr, sizeof(mul_adr));
42         sleep(2);
43     }
44     fclose(fp);
45     close(send_sock);
46     return 0;
47 }
48 
49 void error_handling(char *message)
50 {
51     fputs(message, stderr);
52     fputc('\n', stderr);
53     exit(1);
54 }

 

 

 

 news_receiver.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define BUF_SIZE 30
 9 void error_handling(char *message);
10 
11 int main(int argc, char *argv[])
12 {
13     int recv_sock;
14     int str_len;
15     char buf[BUF_SIZE];
16     struct sockaddr_in adr;
17     struct ip_mreq join_adr;
18     
19     if(argc!=3) {
20         printf("Usage : %s <GroupIP> <PORT>\n", argv[0]);
21         exit(1);
22      }
23   
24     recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
25      memset(&adr, 0, sizeof(adr));
26     adr.sin_family=AF_INET;
27     adr.sin_addr.s_addr=htonl(INADDR_ANY);    
28     adr.sin_port=htons(atoi(argv[2]));
29     
30     if(bind(recv_sock, (struct sockaddr*) &adr, sizeof(adr))==-1)
31         error_handling("bind() error");
32     
33     join_adr.imr_multiaddr.s_addr=inet_addr(argv[1]);
34     join_adr.imr_interface.s_addr=htonl(INADDR_ANY);
35       
36     setsockopt(recv_sock, IPPROTO_IP, 
37         IP_ADD_MEMBERSHIP, (void*)&join_adr, sizeof(join_adr));
38   
39     while(1)
40     {
41         str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
42         if(str_len<0) 
43             break;
44         buf[str_len]=0;
45         fputs(buf, stdout);
46     }
47     close(recv_sock);
48     return 0;
49 }
50 
51 void error_handling(char *message)
52 {
53     fputs(message, stderr);
54     fputc('\n', stderr);
55     exit(1);
56 }

首先先创建news.txt ,往里面写入I LOVE YOU !!!!

 

 

 

 

 

 

 

 

 

 

 

14.2.2 实现广播数据的 Sender 和 Receiver

下面是广播数据的 Sender 和 Receiver的代码:

news_sender_brd.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define BUF_SIZE 30
 9 void error_handling(char *message);
10 
11 int main(int argc, char *argv[])
12 {
13     int send_sock;
14     struct sockaddr_in broad_adr;
15     FILE *fp;
16     char buf[BUF_SIZE];
17     int so_brd=1;
18     
19     if(argc!=3) {
20         printf("Usage : %s <Boradcast IP> <PORT>\n", argv[0]);
21         exit(1);
22     }
23   
24     send_sock=socket(PF_INET, SOCK_DGRAM, 0);    
25     memset(&broad_adr, 0, sizeof(broad_adr));
26     broad_adr.sin_family=AF_INET;
27     broad_adr.sin_addr.s_addr=inet_addr(argv[1]);
28     broad_adr.sin_port=htons(atoi(argv[2]));
29     
30     setsockopt(send_sock, SOL_SOCKET, 
31         SO_BROADCAST, (void*)&so_brd, sizeof(so_brd));    
32     if((fp=fopen("news.txt", "r"))==NULL)
33         error_handling("fopen() error");
34 
35     while(!feof(fp))
36     {
37         fgets(buf, BUF_SIZE, fp);
38         sendto(send_sock, buf, strlen(buf), 
39             0, (struct sockaddr*)&broad_adr, sizeof(broad_adr));
40         sleep(2);
41     }
42 
43     close(send_sock);
44     return 0;
45 }
46 
47 void error_handling(char *message)
48 {
49     fputs(message, stderr);
50     fputc('\n', stderr);
51     exit(1);
52 }

news_receiver_brd.c

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <arpa/inet.h>
 6 #include <sys/socket.h>
 7 
 8 #define BUF_SIZE 30
 9 void error_handling(char *message);
10 
11 int main(int argc, char *argv[])
12 {
13     int recv_sock;
14     struct sockaddr_in adr;
15     int str_len;
16     char buf[BUF_SIZE];
17     
18     if(argc!=2) {
19         printf("Usage : %s  <PORT>\n", argv[0]);
20         exit(1);
21      }
22   
23     recv_sock=socket(PF_INET, SOCK_DGRAM, 0);
24     
25     memset(&adr, 0, sizeof(adr));
26     adr.sin_family=AF_INET;
27     adr.sin_addr.s_addr=htonl(INADDR_ANY);    
28     adr.sin_port=htons(atoi(argv[1]));
29     
30     if(bind(recv_sock, (struct sockaddr*)&adr, sizeof(adr))==-1)
31         error_handling("bind() error");
32   
33     while(1)
34     {
35         str_len=recvfrom(recv_sock, buf, BUF_SIZE-1, 0, NULL, 0);
36         if(str_len<0) 
37             break;
38         buf[str_len]=0;
39         fputs(buf, stdout);
40     }
41     
42     close(recv_sock);
43     return 0;
44 }
45 
46 void error_handling(char *message)
47 {
48     fputs(message, stderr);
49     fputc('\n', stderr);
50     exit(1);
51 }

 

 

14.4 习题

以下答案仅代表本人个人观点,可能不是正确答案。

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

    答:TTL 是决定「数据包传递距离」的主要因素。TTL 每经过一个路由器就减一。TTL 变为 0 时,数据包就无法再被传递,只能销毁。因此,TTL设置过大会影响网络流量。当然,设置过小无法传递到目标。

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

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

  3. 下面关于多播的说法描述错误的是?

    答:以下内容加粗的为描述正确

    1. 多播是用来加入多播组的所有主机传输数据的协议
    2. 主机连接到同一网络才能加入到多播组,也就是说,多播组无法跨越多个网络
    3. 能够加入多播组的主机数并无限制,但只能有 1个主机(Sender)向该组发送数据
    4. 多播时使用的套接字是 UDP 套接字,因为多播是基于 UDP 进行数据通信的。
  4. 多播也对网络流量有利,请比较 TCP 交换方式解释其原因

    答:TCP 是必须建立一对一的连接,如果要向1000个主机发送文件,就得传递1000次。但是此时用多播方式传输数据,就只需要发送一次。

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

    答:可以理解为「通过网络中的特殊协议工作的软件概念上的网络」。也就是说, MBone 并非可以触及的物理网络。他是以物理网络为基础,通过软件方法实现的多播通信必备虚拟网络。

 

posted @ 2019-11-18 23:49  JasonPeng1  阅读(330)  评论(0编辑  收藏  举报