TCP選項之SO_RCVBUF和SO_SNDBUF


每個TCP socket在內核中都有一個發送緩沖區和一個接收緩沖區,TCP的全雙工的工作模式以及TCP的滑動窗口便是依賴於這兩個獨立的buffer以及此buffer的填充狀態。接收緩沖區把數據緩存入內核,應用進程一直沒有調用read進行讀取的話,此數據會一直緩存在相應socket的接收緩沖區內。再啰嗦一點,不管進程是否讀取socket,對端發來的數據都會經由內核接收並且緩存到socket的內核接收緩沖區之中。read所做的工作,就是把內核緩沖區中的數據拷貝到應用層用戶的buffer里面,僅此而已。進程調用send發送的數據的時候,最簡單情況(也是一般情況),將數據拷貝進入socket的內核發送緩沖區之中,然后send便會在上層返回。換句話說,send返回之時,數據不一定會發送到對端去(和write寫文件有點類似),send僅僅是把應用層buffer的數據拷貝進socket的內核發送buffer中。

每個UDP socket都有一個接收緩沖區,沒有發送緩沖區,從概念上來說就是只要有數據就發,不管對方是否可以正確接收,所以不緩沖,不需要發送緩沖區。

接收緩沖區被TCP和UDP用來緩存網絡上來的數據,一直保存到應用進程讀走為止。對於TCP,如果應用進程一直沒有讀取,buffer滿了之后,發生的動作是:通知對端TCP協議中的窗口關閉。這個便是滑動窗口的實現。保證TCP套接口接收緩沖區不會溢出,從而保證了TCP是可靠傳輸。因為對方不允許發出超過所通告窗口大小的數據。 這就是TCP的流量控制,如果對方無視窗口大小而發出了超過窗口大小的數據,則接收方TCP將丟棄它。 UDP:當套接口接收緩沖區滿時,新來的數據報無法進入接收緩沖區,此數據報就被丟棄。UDP是沒有流量控制的;快的發送者可以很容易地就淹沒慢的接收者,導致接收方的UDP丟棄數據報。
以上便是TCP可靠,UDP不可靠的實現。
這兩個選項就是來設置TCP連接的兩個buffer尺寸的。

 

來自:http://blog.chinaunix.net/uid-20726500-id-4949695.html

為了達到最大網絡吞吐,socket send buffer size(SO_SNDBUF)不應該小於帶寬和延遲的乘積。
之前我遇到2個性能問題,都和SO_SNDBUF設置得太小有關。
但是,寫程序的時候可能並不知道把SO_SNDBUF設多大合適,而且SO_SNDBUF也不宜設得太大,浪費內存啊。
於是,有OS提供了動態調整緩沖大小的功能,這樣應用程序就不用再對SO_SNDBUF調優了。
(接受緩沖SO_RCVBUF也是類似的問題,不應該小於帶寬和延遲的乘積)。

 

On Linux:
Linux從2.4開始支持接收緩沖和發送緩沖的動態調整。

http://www.man7.org/linux/man-pages/man7/tcp.7.html
------------------------------------------------------------
       tcp_rmem (since Linux 2.4)
              This is a vector of 3 integers: [min, default, max].  These
              parameters are used by TCP to regulate receive buffer sizes.
              TCP dynamically adjusts the size of the receive buffer from
              the defaults listed below, in the range of these values,
              depending on memory available in the system.
...
       tcp_wmem (since Linux 2.4)
              This is a vector of 3 integers: [min, default, max].  These
              parameters are used by TCP to regulate send buffer sizes.  TCP
              dynamically adjusts the size of the send buffer from the
              default values listed below, in the range of these values,
              depending on memory available.
------------------------------------------------------------

    1. [root@node2 ~]# cat /proc/sys/net/ipv4/tcp_rmem
    2. 4096 87380 4194304
    3. [root@node2 ~]# cat /proc/sys/net/ipv4/tcp_wmem
    4. 4096 16384 4194304

On Windows:
Windows上其實有類似的機能,但是Windows的文檔太糟糕了,我廢了不少勁才找到一些旁證。
從Vista開始Windows引入接受窗口的自動調整
http://blogs.msdn.com/b/wndp/archive/2007/07/05/receive-window-auto-tuning-on-vista.aspx


從Win7和Win2008R2開始Windows引入送信緩沖的自動調整
https://technet.microsoft.com/zh-cn/subscriptions/ms740642.aspx
------------------------------------------------------------ 
Updated for Windows 7 and Windows Server 2008 R2
...
Dynamic send buffering for TCP was added on Windows 7 and Windows Server 2008 R2. As a result, the use of the SIO_IDEAL_SEND_BACKLOG_CHANGE andSIO_IDEAL_SEND_BACKLOG_QUERY IOCTLs are needed only in special circumstances. For more information, see SIO_IDEAL_SEND_BACKLOG_QUERY.
------------------------------------------------------------

需要注意的是,如果應用設置了SO_SNDBUF,Dynamic send buffering會失效 。
https://msdn.microsoft.com/en-us/library/windows/desktop/bb736549(v=vs.85).aspx
------------------------------------------------------------
Dynamic send buffering for TCP was added on Windows 7 and Windows Server 2008 R2. By default, dynamic send buffering for TCP is enabled unless an application sets the SO_SNDBUF socket option on the stream socket.
------------------------------------------------------------

我在MSDN上沒有找到正式介紹這個功能的頁面(也許就沒有這樣的頁面),所以也不知道它的自動調整是怎么個調法,范圍是多少。而且,通過對Win7和Windows Server 2008 R2的測試我也沒看到送信緩沖自動調整的效果,這個效果我只在Windows 2012上看到了。

 

測試:
下面是我的測試,主要針對送信緩沖的。
以下是各OS中送信緩沖的缺省值
OS                      送信緩沖的缺省值(通過getsockopt(SO_SNDBUF)獲取) 
Window7:            8k 
Windows2003:     8k 
Windows2008:     8k 
Windows8:          64k 
Windows2012:     64k

測試方法:
1)機器A(Windows)通過TCP socket向機器B發送100MB數據。
2)機器A每次send()向socket寫入8K字節。
3)機器A的程序設置不同的SO_SNDBUF,查看總送信時間的變化。

測試環境1:
Host A: Windows 2012(x64)
Host B: RHEL6(x64)
Network:1Gbit LAN

Result(execute time):
default(64K),                  1.118s(送信緩沖的自動調整生效) 
set SO_SNDBUF to 32K,   3.295s 
set SO_SNDBUF to 64K,   2.048s 
set SO_SNDBUF to 128K, 1.404s 
set SO_SNDBUF to 256K, 1.290s

從上面可以看出, Windows 2012中送信緩沖的自動調整還是很有效果的。
注)如果使用Windows而不是Linux作為客戶端,效果也是一樣的


測試環境2:
Host A: Windows 2008 R2(x64)

Host B: RHEL6(x64)
Network:1Gbit LAN

Result(execute time):
default(8K),                   7.370s 
set SO_SNDBUF to 32K,  4.159s 
set SO_SNDBUF to 64K,  2.875s 
set SO_SNDBUF to 128K, 1.593s 
set SO_SNDBUF to 256K, 1.324s 

對Windows 2008 R2,不知道送信緩沖的自動調整沒有生效("netsh winsock show autotuning"是生效了的),還是8K初始值的起點太低,反正性能不如人意。


結論:
較新的OS都支持socket buffer的自動調整,不需要應用程序去調優。但對Windows 2012(和Win8)以前的Windows,為了達到最大網絡吞吐,還是要應用程序操心一下SO_SNDBUF的設置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM