ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:25.79KB ,
资源ID:7308979      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7308979.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(组播编程.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

组播编程.docx

1、组播编程初识组播(1)我们知道在内核中用结构体struct net_device标识一个网络设备接口,该结构体有一个成员指针ip_ptr,它是留给IPv4协议用于填充协议相关的一些数据的。IPv4协议的模块将其指向一个结构体struct in_device,该结构体含有很多协议相关的数据,比如配置在这个网络设备接口上的所有的IPv4的地址,该网络设备接口接受的组播地址等,下面是其完整的定义: struct in_device struct net_device *dev; atomic_t refcnt; int dead; struct in_ifaddr *ifa_list; /IP地址列

2、表 rwlock_t mc_list_lock; struct ip_mc_list *mc_list; /IP组播过滤列表。 spinlock_t mc_tomb_lock; /下面都是组播相关数据。 struct ip_mc_list *mc_tomb; unsigned long mr_v1_seen; unsigned long mr_v2_seen; unsigned long mr_maxdelay; unsigned char mr_qrv; unsigned char mr_gq_running; unsigned char mr_ifc_count; struct timer

3、_list mr_gq_timer; /* general query timer */ struct timer_list mr_ifc_timer; /* interface change timer */ struct neigh_parms *arp_parms; struct ipv4_devconf cnf; struct rcu_head rcu_head; ; 我们暂时还无法完全理解这个结构体,目前只需关注的是mc_list成员,这是关于组播的一个最为关键的数据结构。mc_list是一个链表,链表的一个结点代表一个组播地址(也就是一个多播组的组号),代表这个网络设备接口已经加入

4、了这个组播组,需要接收来自这个组的数据报。下面是该节点的结构体定义: struct ip_mc_list struct in_device *interface; unsigned long multiaddr; struct ip_sf_list *sources; struct ip_sf_list *tomb; unsigned int sfmode; unsigned long sfcount2; struct ip_mc_list *next; struct timer_list timer; int users; atomic_t refcnt; spinlock_t lock;

5、char tm_running; char reporter; char unsolicit_count; char loaded; unsigned char gsquery; unsigned char crcount; ; 同样,我们把其中的大部分成员留待以后理解。multiaddr就是组播地址,sources和tomb是关于组播源地址的一个列表,sfmode和sfcount是过滤参数,也就是说,该网络设备接口虽然加入了某个组播组,但对某些主机向该组发的数据报不接收,或者只接收某个主机发向该组的数据报,这就要对组播源进行过滤。 关于D类地址的常识,这里不再介绍,可参考相关书籍。 下面介绍

6、一个特殊的组播地址224.0.0.1,它标识子网中的所有主机,同一个子网内具有组播功能的主机都属于这个组。我们的my_inet模块在初始化时,myinetdev_event函数收到网络设备接口启动(NETDEV_UP)的消息后,调用myip_mc_up启动组播功能。 启动组播功能的第一件事便是把本机加入到这个特殊的组播组IGMP_ALL_HOSTS(即224.0.0.1),调用myip_mc_inc_group函数完成加入动作。因为我们的my_inet模块是作为系统中的第二个IPv4模块,在系统正常运行后被加载的,所以,网络设备接口早已完成了加入该组播组的操作。my_inet模块的加入动作是只

7、是简单地将成员users加1,然后调用myip_mc_add_src函数加入组播源过滤。 IGMP_ALL_HOSTS组的sources为NULL,sfmode为MCAST_EXCLUDE(过滤掉sources中列出的所有源),所以结果是不过滤任何组播源。myip_mc_add_src函数中,将sfcountMCAST_EXCLUDE的值加1,表示新增一个过滤机制。 初识组播(2)上一篇我们讲到,因为my_inet是系统中第二个加载的IPv4模块,所以网络设备接口早已完成了加入IGMP_ALL_HOST组的操作,my_inet只是简单增加引用计数和源过滤计数,下面我们来看看,第一个加载的IPv

8、4模块(即内核原有的TCP/IP协议栈模块)是如何把网络设备接口加入IGMP_ALL_HOST组的。 在myip_mc_inc_group函数中,首先检查in_device-mc_list列表中已加入的组播组,看本接口是否已经加入了IGMP_ALL_HOST组,结果当然是没有。则,首先创建一个新的结构体struct ip_mc_list *im,初始化其成员值,设成员multiaddr为组播地址224.0.0.1,sf_mode为MCAST_EXCLUDE,sfcountMCAST_EXCLUDE为1,sources为NULL,表示使用一个源过滤机制,该机制不过滤任何组播源。成员loaded为

9、0,表示该组播组尚未被载入(稍后将看到载入的操作)。初始化完成后,将这个新的组播组加入到mc_list链表的表头。 前面讲到过,mc_tomb也是in_device的一个成员,也表示一个组播组列表,这个列表中的组应该是不活跃的(当前不在使用的,具体留待以后分析),新的组加入到mc_list成功后,还要到这个列表中查找,看是否也存在于这个列表中,如果存在,要删除,因为该组当前是活跃的。 最后,调用myigmp_group_added完成真正的加入组播组的操作,对于IGMP_ALL_HOST这个组来讲,该函数做的事情相对比较少,它检查loaded成员,发现为0,则调用myip_mc_filter_

10、add,加入一个网络设备级的组播地址。也就是说,代表网络设备接口的结构体struct net_device有一个成员mc_list,它是一个链表,每个结点代表一个组播组的mac地址。与in_device的mc_list中的组播IP地址对应。loaded为0时,我们要做的事情就是把IP地址224.0.0.1映射成一个mac地址加到net_device的mc_list链表中去,然后把loaded置1,该成员的结点定义如下: struct dev_mc_list struct dev_mc_list *next; _u8 dmi_addrMAX_ADDR_LEN; unsigned char dmi

11、_addrlen; int dmi_users; int dmi_gusers; ; dmi_addr是mac地址,dmi_addrlen是地址长度,dmi_users是引用计数。添加完成后,net_device的成员mc_count相应的加1。 下面我们来看看组播IP地址是如何被映射成组播mac地址的。一个mac地址总共有6字节,48位,被分成两段:前3字节和后3字节,前3字节用于标识网卡的制造厂商,其中第40位(第一字节的最低位)用于标识组播,所以在网卡的mac地址中必须置0,后3字节是厂商内部使用的序列号。一个组播IP地址映射成mac地址的规则是:前三字节强制置01:00:5E,后3字节

12、中,第23位置0,0-22位放入IP地址的0-23位。 加入一个组播组网络中的一台主机如果希望能够接收到来自网络中其它主机发往某一个组播组的数据报,那么这么主机必须先加入该组播组,然后就可以从组地址接收数据包。在广域网中,还涉及到路由器支持组播路由等,但本文希望以一个最为简单的例子解释清楚协议栈关于组播的一个最为简单明了的工作过程,甚至,我们不希望涉及到IGMP包。 我们先从一个组播客户端的应用程序入手来解析组播的工作过程: #include #include #include #include #include my_inet.h#include #define MAXBUF 256#def

13、ine PUERTO 5000#define GRUPO 224.0.1.1int main(void) int fd, n, r; struct sockaddr_in srv, cli; struct ip_mreq mreq; char bufMAXBUF; memset( &srv, 0, sizeof(struct sockaddr_in) ); memset( &cli, 0, sizeof(struct sockaddr_in) ); memset( &mreq, 0, sizeof(struct ip_mreq) ); srv.sin_family = MY_AF_INET;

14、srv.sin_port = htons(PUERTO); if( inet_aton(GRUPO, &srv.sin_addr ) 0 ) perror(inet_aton); return -1; if( (fd = socket( MY_AF_INET, SOCK_DGRAM, MY_IPPROTO_UDP) ) 0 ) perror(socket); return -1; if( bind(fd, (struct sockaddr *)&srv, sizeof(srv) 0 ) perror(bind); return -1; if (inet_aton(GRUPO, &mreq.im

15、r_multiaddr) 0) perror(inet_aton); return -1; inet_aton( 172.16.48.2, &(mreq.imr_interface) ); if( setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,sizeof(mreq) 0 ) perror(setsockopt); return -1; n = sizeof(cli); while(1) if( (r = recvfrom(fd, buf, MAXBUF, 0, (struct sockaddr *)&cli, (socklen_t*)&n)

16、mc_list; /新节点放到链表头。 .multi =传入的参数; /这是关键的组信息。 .sfmode = MCAST_EXCLUDE; /过滤掉sflist中的所有源。 .sflist = NULL; /没有源需要过滤。 ; 最后,调用myip_mc_inc_group函数在struct in_device和struct net_device的mc_list链表中都添上相应的组播组节点,关于这部分的细节可以在前一篇文章初识组播2中找到。不再重复。 到此为止,我们完成了最为简单的加入组播组的操作,对于同一子网内的情况,socket已经可以接收组播数据了,关于组播数据如何接收,下回分解。 接

17、收组播数据报前面我们讲到如何加入到一个组播组中,当一个客户端完成了加入一个组播组的操作后,就可以从该组接收数据了。下面我们看看组播数据报接收的详细流程。 通过加入组播组的操作后,网络设备接口已经知道要接收该组的数据报,所以组播数据会从网卡接收进来,一直到达myip_rcv函数,我们就从myip_rcv函数开始,跟踪整个组播数据报的接收流程。 同样,myip_rcv还是先检查数据报的类型(是否为本机需要接收的包),ip首部是否正确,然后调用myip_rcv_finish。myip_rcv_finish对任何数据报都要先查找输入路由,输入路由查找函数是myip_route_input,当该函数在路

18、由缓存myrt_hash_table中找不到相应的路由项时,判断数据报的输入地址,如果发现是组播地址,就不能简单地查找FIB,而是要作特殊处理。 首先,调用myip_check_mc对这个组播数据报作检查,从网络设备接口的struct in_device中去匹配组播地址,如果匹配不到,表示这个不是我们希望接收的组播包,丢弃。匹配到了,则作下一步检查,如果这本身就是一个IGMP包,则接收,否则,查看这个组播组在我们的struct in_device中设置的过滤机制,如果该数据报的源地址在我们的过滤名单中,则丢弃,否则接收。 如果检查通过,准备接收这个组播包,则调用myip_route_input

19、_mc查找组播输入路由,这是一个专门为组播设置的函数,它第一步要检查数据报源地址的有效性,即源地址不能是组播地址,不能是广播地址,也不能是回环地址,同时,该数据报必须是一个因特网协议包(ETH_P_IP)。如果源地址为0,那么只有当目的地址是224.0.0.0-224.0.0.255之间的值(只能在发送主机所在的一个子网内的传送,不会通过路由器转发。)时,系统可以自己选定一个scope为RT_SCOPE_LINK的源地址,否则出错。 当验证了源地址的有效性之后,我们建立路由项,即结构体struct rtable。该路由项的rt_type值是RTN_MULTICAST,表示这一条组播路由。对于本

20、地接收的组播包,我们设置接收函数为myip_local_deliver。 有了这个路由项,我们可以通过调用myip_local_deliver,继续接收流程,这部分流程前面已有多次介绍,所以讲得简单一点,只注意组播特有的。同样,到myip_local_deliver_finish后,首先要检查是否有raw socket要接收这个组播包。然后根据IP首部里协议字段,调用相应协议的接收函数,我们这儿是一个UDP组播包,所以调用myudp_rcv。 myudp_rcv首先会对路由项的成员rt_flags作一个检查,如果发现它有RTCF_BROADCAST或者RTCF_MULTICAST,就不会走常规

21、的从myudp_hash中匹配源和目的地址,找到socket,把数据报放入接收队列这么一个流程。而是调用函数myudp_v4_mcast_deliver,这是一个专用于接收UDP组播数据报的函数,它首先根据目的端口确定在哈希表mydup_hash中的位置,然后遍历找到的这个链表。与普通的UDP数据报接收相比,它多一个过滤检查,即在套接字结构体的成员mc_list中找到与该数据报所属组对应的ip_mc_socklist项,查看它的过滤配置,确认该数据报的源地址是否在过滤列表中。如果不在,则把数据放到该socket的接收队列中,完成组播数据报的接收。 关于组播的其它几个选项前面我们已经讲到了加入一

22、个组播组的IP选项IP_ADD_MEMBERSHIP,关于组播的IP选项,除了这个,还有总共四个,它们分别是IP_DROP_MEMBERSHIP,IP_MULTICAST_IF,IP_MULTICAST_TTL,IP_MULTICAST_LOOP,下面分别一一介绍。 IP_DROP_MEMBERSHIP表示退出一个组播组,该选项最终会调用内核函数myip_mc_leave_group。该函数首先拿到结构体struct in_device,取走要离开的组的源过滤机制,即从in_device-mc_list中找到对应的组struct ip_mc_list,将其成员sfcountsfmode减一,然

23、后从其成员sources中取走相应的过滤源。然后将in_device-mc_list中该组所在的节点的引用计数减一,如果引用计数已经减为零了,则清struct net_device和struct in_device中该组的记录。最后,套接字结构体struct inet_sock的成员mc_list中有关该组的节点也被删除。至此,完成离开一个组播组的操作,该选项的参数是结构体struct ip_mreq,同IP_ADD_MEMBERSHIP。 IP_MULTICAST_IF是一个用于确定提交组播报文的接口,它的参数也是struct ip_mreq,通过该参数指定发送组播报文所使用的本地IP地址和

24、本地网络设备接口的索引号,用于发送组播数据报,这两个值确定后放在套接字的结构体struct inet_sock的成员mc_addr和mc_index中,以备发送组播数据报时查询。 IP_MULTICAST_TTL指定提交的组播报文的TTL,有效的TTL在0到255之间,该选项提供的参数会被赋给套接字结构体struct inet_sock的成员mc_ttl。以备发送组播数据报时查询。 IP_MULTICAST_LOOP使组播报文环路有效或无效,如果环路有效,则在发送组播报文的时候,会给环回接口也发一份。该值存放在套接字的结构体struct inet_sock的成员mc_loop中。 以上IP_M

25、ULTICAST_IF,IP_MULTICAST_TTL和IP_MULTICAST_LOOP三项都是跟组播报文发送相关的选项,在接下来的发送组播数据报的分析中会再次提到。 发送组播数据报(1)我们还是以发送UDP的组播数据为例。其实发送一个UDP的组播数据报跟发送一个单播UDP数据报的差别并不大。 首先是在myudp_sendmsg函数中,如果发送接口的源地址没有确定,并且目的地址是组播地址的话,则源地址使用inet_sock-mc_addr。而发送接口的源地址首先是通过inet_sock-saddr来确定的,如果发现inet_sock-saddr为零,才会采用inet_sock-mc_addr的值。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1