Linux下的SO_REUSEADDR

《TCP/IP詳解 卷1:協議》第18章 TCP的建立與終止 P185

原文:Linux下SO_REUSEADDR於TCP/IPv1中的差異

  TCP/IPv1 老矣! Richard 的去世, 使得這部經典一直無人更新, 雖然書中對IPv4下TCP/IP協議有着清晰的描述, 但是互聯網技術日新月異, 一些老的技術不斷被改善, 更新以及被取代, 但是書本留在94年成書後就沒有任何改變了, 完全沒有涉及LINUX和IPv6等等.

  迴歸正題.

  在Linux下socket API中的socket選項SO_REUSEADDR完全不同於TCP/IPv1中描述(那麼就應該不同與大部分UNIX下的功能).

  首先說明本文中IP相同的定義: 除了一般意義上的相同, 通配IP(也就是INADDR_ANY, 或者*)和任何IP相同.

  在UDP下:

    1.在LINUX下, 綁定相同端口(port)不同IP不需要任何額外的操作; 而在書中指出, 綁定相同端口不同IP需要在除了第一次綁定外的所有後續綁定前聲明SO_REUSEADDR, 並且在這種情況下可以綁定通配IP地址(例如綁定了192.168.1.2:12345 後使用SO_REUSEADDR就可以綁定*:12345, 而在linux這是不可行的).

    2. 在LINUX下, 綁定相同端口相同IP需要在每一次綁定(包括第一次)前聲明SO_REUSEADDR, 綁定後如果收到多播或者廣播的數據報, 那麼每一個綁定該IP和端口的socket都可以收到這個數據報, 如果是收到單播的話就只有一個程序收到這個數據報(據說是最後一個綁定該IP:port的socket); 這和書中指出的做法基本相同, 除了某些unix系統(4.4BSD)使用的是SO_REUSEPORT, 而LINUX下無此選項, 另外如果linux需要綁定某個接口的IP和通配IP和相同端口(如192.168.1.2:12345和*:12345), 那麼應該每次綁定前都聲明SO_REUSEADDR這個選項.

  在TCP下:

    1. TCP要求正在使用的IP:port(處於TIME_WAIT狀態的除外)不能通過任何形式來重用, 以防止端口盜用(TCP是面向鏈接的協議, 通過一個socket pair四元組確定一個鏈接, 如果鏈接的一端兩個socket都能綁定同一個IP:port, 那麼就破壞了四元組關係, 到底哪個socket應該收到數據就無法確定). 雖然某些系統能夠這樣做, 但是我們不應該違反約定而去做一些不兼容的coding. LINUX不支持這種操作.

    2. 對於綁定不同IP相同端口的情況, LINUX也不需要任何操作, 這種情況和UDP的第一種完全一樣, 和TCP/IPv1中的區別也和UDP的第一種完全一樣, 因此, 在linux下TCP不能同時綁定某個接口的IP和通配地址的相同端口.

    3. 對於處於TIME_WAIT的鏈接的複用, TCP要求的是可以複用構成TIME_WAIT socket pair中的本機IP:port, 當不可使用這個IP:port去與TIME_WAIT socket pair 的另外一端的IP’:port’建立鏈接. 而在linux下, 這麼做是可行的, 只要在每次綁定之前聲明SO_REUSEADDR, 那麼就可以重用正在TIME_WAIT的socket pair, 反之如果沒有每次綁定前都聲明好SO_REUSEADDR, 那麼無論如何都無法重用正在TIME_WAIT的本機IP:port(即使這個IP:port和另外一端的IP:port構成的socket pair不是TIME_WAIT的socket pair, 並且必須每次都聲明SO_REUSEADDR, 即使除了第一次之外都聲明瞭SO_REUSEADDR, 都會綁定失敗); 而在TCP/IPv1中描述的是, 只要在後續的綁定前聲明好SO_REUSEADDR, 那麼就可以綁定正在處於TIME_WAIT的本機IP:port, 只要不要再去connect那個和本機IP:port構成TIME_WAIT socket pair的就好(如果這麼做connect會失敗).

  綜合來說, linux下對SO_REUSEADDR的實現應該不同unix下的實現, 在設計網絡程序時, 如果我們不想要讓別的程序分享我們使用的IP:port, 那麼就不要在綁定前設置SO_REUSEADDR, 反之, 如果我們願意這麼做, 那麼最後在每次綁定前都先設置好這個值.

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