分类:
2010-09-23 15:34:47
SO_BINDTODEVICE 套接口选项
2008-03-31 11:23
1. 起因 事情的起因是我准备用两个CDMA modem来拓展点对点连接的带宽,并且希望藉此实现两个modem之间的负载均衡。但是不幸的是,联通公司的接入设备不支持Multilink-PPP。于是,没有办法,我只好自己来实现负载均衡。实现负载均衡的办法有几种,网络上给出的一种办法是采用iproute2来完成包级别的负载均衡,这是在内核一级实现的。但是我并不想把一切都交给内核去完成,我希望能够自己控制每一个modem上的流量。那么,我应该怎么办呢? 2. 解决方案 一开始,我想到的办法是创建两个套接口,然后将每个套接口都绑定到一个本地IP地址上,我以为这样将会导致数据从所绑定的IP地址所在的网络设备上发出去。但是实践证明这种想法是错误的。因为每次在发送数据包之前,内核都要查找路由表来决定从哪个网络接口上发送数据包。一旦找到一个合适的路由表项,就从该路由表项所指出的网络接口上将数据包发送出去。这样,就有一个问题,由于路由表是高速缓存的,因此每次发送数据包之后,发送数据包的那个接口将会有更大的机会被内核再一次选中。在最坏的情况下,将导致一个modem忙得不可开交,而另一个modem却“无人问津”。这显然违背了我的初衷。试验结果表明,当一个modem上发送了几百KB的数据之后,另外一个上仍然只发送了几十个B。看来,此路不通! 循着上述思路,一种稍微令人错愕的做法是每次发送数据包之前,都先调整路由表。调整路由表是很容易做到的。但是这样做的话也实在太麻烦了一点,所以,此想法也被我抛弃了。我甚至没有测试此法是否可行,但是从理论上来说是行得通的。而且,在网上介绍的方法中,路由级别的负载均衡好像就是这样来实现的,不过,仅仅是好像而已,我并没有深究。 几番尝试未果之后,我把《UNIX网络编程》搬了出来,把UDP有关的部分细细地筛了一遍。只发现了一个可能有作用的地方:可以通过setsockopt()设置一个套接口选项:SO_DONTROUTE,但是对该选项的作用说得比较含糊。含糊归含糊,我还是实际尝试了一下,结果仍然是不行,原因未知。 于是,我不得不回到Linux本身,对着浩浩荡荡的一大堆man手册读起来。当我看到socket(7)的时候,忽然看到了一个令我眼前一亮的套接口选项:SO_BINDTODEVICE。从字面上看,这个选项应该就是我要的了。后来的试验结果证明事实的确如此。 在socket(7)中对该套接口选项的说明如下: SO_BINDTODEVICE Bind this socket to a particular device like "eth0", as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, on 给主人留下些什么吧!~~
|