SO_BINDTODEVICE 套接口選項

這是一篇我看了以後感覺非常棒的文章. 實在忍不住要轉載..

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, only packets received from that particular interface are processed by the socket. Note that this   only   works   for   some   s

博客推薦文章
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章