Chinaunix首页 | 论坛 | 博客
  • 博客访问: 73403
  • 博文数量: 35
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 140
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-11 10:56
文章分类

全部博文(35)

文章存档

2016年(2)

2015年(33)

我的朋友

分类: LINUX

2015-05-05 14:18:16

内核中的多播
Linux内核中的多播是利用结构struct ip_mc_socklist来将多播的各个方面连接起来的,其示意图如图11.7所示。
 

 
 
1.  struct inet_sock {  
2.      ...  
3.      __u8                mc_ttl;     /*多播TTL*/  
4.      ...  
5.      __u8                ...  
6.                          mc_loop:1;      /*多播回环设置*/  
7.      int                 mc_index;       /*多播设备序号*/  
8.      __be32              mc_addr;        /*多播地址*/  
9.      struct ip_mc_socklist   *mc_list;   /*多播群数组*/  
10.    ...  
11.}; 
结构成员mc_ttl用于控制多播的TTL
结构成员mc_loop表示是否回环有效,用于控制多播数据的本地发送;
结构成员mc_index用于表示网络设备的序号;
结构成员mc_addr用于保存多播的地址;
结构成员mc_list用于保存多播的群组。
1.结构ip_mc_socklist
结构成员mc_list的原型为struct ip_mc_socklist,定义如下:
1.  struct ip_mc_socklist  
2.  {  
3.      struct ip_mc_socklist   *next;  
4.      struct ip_mreqn     multi;  
5.      unsigned int        sfmode;     /*MCAST_{INCLUDE,EXCLUDE}*/  
6.      struct ip_sf_socklist   *sflist;  
7.  }; 
成员参数next指向链表的下一个节点。
成员参数multi表示组信息,即在哪一个本地接口上,加入到哪一个多播组。
成员参数sfmode是过滤模式,取值为 MCAST_INCLUDEMCAST_EXCLUDE,分别表示只接收sflist所列出的那些源的多播数据报,和不接收sflist所列出的那些源的多播数据报。
成员参数sflist是源列表。
2.结构ip_mreqn
multi成员的原型为结构struct ip_mreqn,定义如下:
1.  struct ip_mreqn  
2.  {  
3.      struct in_addr  imr_multiaddr;      /*多播组的IP地址*/  
4.      struct in_addr  imr_address;        /*本地址网络接口的IP地址*/  
5.      int         imr_ifindex;            /*网络接口序号*/  
6.  }; 
该结构体的两个成员分别用于指定所加入的多播组的组IP地址,和所要加入组的那个本地接口的IP地址。该命令字没有源过滤的功能,它相当于实现IGMPv1的多播加入服务接口。
3.结构ip_sf_socklist
成员sflist的原型为结构struct ip_sf_socklist,定义如下:
1.  struct ip_sf_socklist  
2.  {  
3.      unsigned int    sl_max;     /*当前sl_addr数组的最大可容纳量*/  
4.      unsigned int    sl_count;   /*源地址列表中源地址的数量*/  
5.      __u32         sl_addr[0];       /*源地址列表*/  
6.  }; 
成员参数sl_addr表示是源地址列表;
成员参数sl_count表示是源地址列表中源地址的数量;
成员参数sl_max表示是当前sl_addr数组的最大可容纳量(不确定)。
4.选项IP_ADD_MEMBERSHIP
选项IP_ADD_MEMBERSHIP用于把一个本地的IP地址加入到一个多播组,在内核中 其处理过程如图11.8所示,在应用层调用函数setsockopt()函数的选项IP_ADD_MEMBE- RSHIP后,内核的处理过程如下,主要调用了函数ip_mc_join_group()
 
 

1)将用户数据复制如内核。
2)判断广播IP地址是否合法。
3)查找IP地址对应的网络接口。
4)查找多播列表中是否已经存在多播地址。
5)将此多播地址加入列表。
6)返回处理值。
5.选项IP_DROP_MEMBERSHIP
选项IP_DROP_MEMBERSHIP用于把一个本地的IP地址从一个多播组中取出,在内核中其处理过程如图11.9所示,在应用层调用 setsockopt()函数的选项IP_DROP_ MEMBERSHIP后,内核的处理过程如下,主要调用了函数ip_mc_leave_group()
 
 
 
1)将用户数据复制入内核。
2)查找IP地址对应的网络接口。
3)查找多播列表中是否已经存在多播地址。
4)将此多播地址从源地址中取出。
5)将此地址结构从多播列表中取出。
6)返回处理值。
 



一个组播通信的例子

  

  下面给出一个简单的例子实现文中阐述的思想:由一个进程向一个组播组发送报文,组播组中的相关进程接收报文,并将报文显示到屏幕上。

  

  下面的代码实现了一个服务进程,它将标准输入接口输入的信息全部发送到组播组 224.0.1.1。你会发现,将信息发送到组播组不需要特别的操作,只要设置好组播组的目的地址就足够了。若在开发过程中,Loopback和TTL这两个选项的默认值不适合应用程序,可以加以调整。

  

  服务程序

  

  将标准输入端口的输入发送到组播组224.0.1.1。

  

  #include

  #include

  #include

  #include

  #include

  #include

  #define MAXBUF 256

  #define PUERTO 5000

  #define GROUP "224.0.1.1"

  int main(void) {

  int s;

  struct sockaddr_in srv;

  char buf;

  bzero(&srv, sizeof(srv));

  srv.sin_family = AF_INET;

  srv.sin_port = htons(PUERTO);

  if (inet_aton(GRUPO, &srv.sin_addr) < 0) {

  perror("inet_aton");

  return 1;

  }

  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {

  perror("socket");

  return 1;

  }

  while (fgets(buf, MAXBUF, stdin)) {

  if (sendto(s, buf, strlen(buf), 0,

  (struct sockaddr *)&srv, sizeof(srv)) < 0) {

  perror("recvfrom");

  } else {

  fprintf(stdout, "Enviado a %s: %s

  ", GRUPO, buf);

  }

  }

  }

客户端程序

  #include

  #include

  #include

  #include

  #include

  #include

  #define MAXBUF 256

  #define PUERTO 5000

  #define GROUP "224.0.1.1"

  int main(void) {

  int s, n, r;

  struct sockaddr_in srv, cli;

  struct ip_mreq mreq;

  char buf;

  bzero(&srv, sizeof(srv));

  srv.sin_family = AF_INET;

  srv.sin_port = htons(PUERTO);

  if (inet_aton(GRUPO, &srv.sin_addr) < 0) {

  perror("inet_aton");

  return 1;

  }

  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {

  perror("socket");

  return 1;

  }

  if (bind(s, (struct sockaddr *)&srv, sizeof(srv)) < 0) {

  perror("bind");

  return 1;

  }

  if (inet_aton(GRUPO, &mreq.imr_multiaddr) < 0) {

  perror("inet_aton");

  return 1;

  }

  mreq.imr_interface.s_addr = htonl(INADDR_ANY);

  if (setsockopt(s,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq))

  < 0) {

  perror("setsockopt");

  return 1;

  }

  n = sizeof(cli);

  while (1) {

  if ((r = recvfrom(s, buf, MAXBUF, 0, (struct sockaddr *)

  &cli, &n)) < 0) {

  perror("recvfrom");

  } else {

  buf = 0;

  fprintf(stdout, "Mensaje desde %s: %s

  ",

  inet_ntoa(cli.sin_addr), buf);

  }

  }

  }

阅读(1385) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~