组播的时候到底该如何绑定网卡

来源:互联网 发布:luxsens 人工智能 编辑:程序博客网 时间:2024/05/21 11:10

http://blog.hongquan.me/?p=114

以前在代码中,遇到组播都是一直绑定0.0.0.0然后去把自己加入到组播组里面去。但是最近的一次改动却让我发现了一个问题。

因为在显示的环境中机器上会有很多网卡(>3)。 而我们指向接收其中一个子网中的组播中的数据,那么很明显的想法就是接收端绑定相应子网的IP。在windows环境中,我们绑定了机器上该子网的IP(例如:172.16.20.40)。实际测试的发现一切良好。然后在Linux环境中沿用了这个code。结果却发现无论如何都收不到组播消息。于是一阵瞎倒腾,发现在linux上绑定在组播组的地址上就可以收到消息。晕,系统不一样表现就是不一样啊。但是事情并没有结束,我并没有弄清楚这是咋回事。查看了公司的包装的代码发现在mutilcast client的实现上是按照Windows的设定来的。

  1. 创建UDP socket,绑定在一个网卡地址上
  2. 指定multiast group address,并且取出socket的本地地址,填入ip_mreq.imr_multiaddr和ip_mreq.imr_interface。

而google了一番发现了一个问题,在linux上是不能绑定在物理网卡地址上的,这样做会什么信息都收不到,要么绑定0.0.0.0以收取所有的组播消息,或者绑定一个具体的组播地址以收取发到这个组播地址的消息。而具体要收取哪一个子网的组播信息的时候用ip_mreq.imr_interface来指定。详见(http://stackoverflow.com/questions/11234671/multiple-multicast-on-multiple-interfaces 和http://www.kohala.com/start/mcast.api.txt

  看起来一样的东西在不同的系统下面可能是不一样的,谨记,谨记.




关于在双网卡多IP环境下的UDP服务器组件编程问题及解决方案

现行双通机房很多
而双通机房大多是使用多IP,即电信一个网通一个. (也有只使用单IP的双通机房,不过据说效果不好,未验证)
在双IP下,在使用常规方法创建UDP服务(即用一个Socket绑定0.0.0.0,即绑定本机所有IP) 时会产生一个由双IP造成的问题:
假设 本机有电信IP 1 网通IP 2
当一个电信用户A发一个UDP包到电信IP 2,而服务器处理返回时,有可能是用IP 1 发送出去的.
这就造成可能用户A会收不到该UDP返回包,原因是对用户A的防火墙而言IP 1是一个陌生IP,有可能被拒绝了.

解决这个问题的方案比较简单. 只要在创建UDP服务时,为每一个IP创建一个UDP Socket,绑定于不同IP相同端口. 在处理用户UDP时,哪个SOcket接收到的,就用哪个Socket返回.

现有UDP另一个高级问题: 转发问题
假定有用户A,用户B已登录到UDP服务器.
而当有一个业务,是A发请求包,而UDP服务器处理后需发UDP包给B,以通知B.(例,P2P打通,IM上线通知等.)
这个时候,UDP在处理 A请求,问题是当转发B时,该用哪个IP ,即哪个Socket发给B.
如果A和B是通过不同的IP登录上去的. 服务器用了非B通信的Socket发的时候,就会产生可能B接收不到包的问题.

解决这个问题的方案有两个:
1.在用户在线表中记录用户通信的服务器Socket.
2.在UDP层记录用户IP与服务器Socket的通信关系. 在发包时从这关系映射中查找该用哪个Socket发送.

现来分析两种方案的实现方法,及优缺点
1方案,实现简单,在用户在线表中增加一些记录字段即可,优点是性能好. 缺点是在业务层上实现的,会导致业务复杂度增加和应用限制(必须记录用户的在线信息.)
2方案,实现方法是每一个服务Socket建立一个映射表,把通信过的用户IP映射过来.每次须要转发时就从映射表中查找该Socket是否存在该IP.有则使用,无则查询下一个Socket. 都查询不到则使用默认Socket.
该方法的优点的是在UDP组件层就实现了功能,不会限制应用.不影响业务逻辑.
缺点是实现复杂 要采用一种映射算法来存储IP与Socket之间的关系.而实现映射又须要额外的存储空间来实现.
下面讲一下2方案里怎么存储用户IP和服务器Socket之间的映射
具体的实现映射的方法有两种比较实用的,一种是使用HashTable.
优点是精确,缺点是须要的存储空间大.
另一种是使用路由和搜索引擎爬虫中比较常用的BloomFilter.算法
优点是内存占用空间少,缺点是CPU消耗比HashTable高些. 而且不够精确.

现在来比较一下两种算法的存储消耗,CPU现在够强,这部分的CPU消耗基本可以忽略.
以预计映射100W个用户IP与Socket之间的映射为目标.
如果用HashTable,以桶+链表解决冲突的方法,那每一节点须 4(桶)+4链表)+4(IP) 共 12字节
100W即约11M.
如果使用BloomFilter 以8种Hash算法实现 即8位Byte型的BloomFilter. 使用400W节点.约需4M.而冲突率可保证在10W分之一以下(已验证)
两种算法各有优缺点,就看个人喜爱哪种了.
还有一个问题就是什么时候清空这些映射重建.因为UDP的IP映射长久保留是没有意义的.
我的方案是为每一个Socket建两个映射,两个映射建立时间错开3分钟,但每一个映射的存活时间都是6分钟.
即在任何一个时刻,都有一个映射至少记录了3分钟内的IP映射情况.
这部分看大家各自需求是什么样的,一天清一次也可以.
如果哪位朋友有更好的方法欢迎讨论.

原创粉丝点击