1 設置socket tcp緩衝區大小的疑惑linux
疑惑1:經過setsockopt設置SO_SNDBUF、SO_RCVBUF這連個默認緩衝區的值,再用getsockopt獲取設置的值,發現返回值是設置值的兩倍。爲何?shell
經過網上查找,看到linux的內核代碼/usr/src/linux-2.6.13.2/net/core/sock.c,找到sock_setsockopt這個函數的這段代碼:網絡
case SO_SNDBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size' games. RCVBUF/SNDBUF are treated in BSD as hints */ if (val > sysctl_wmem_max)//val是咱們想設置的緩衝區大小的值 val = sysctl_wmem_max;//大於最大值,則val值設置成最大值 sk->sk_userlocks |= SOCK_SNDBUF_LOCK; if ((val * 2) < SOCK_MIN_SNDBUF)//val的兩倍小於最小值,則設置成最小值 sk->sk_sndbuf = SOCK_MIN_SNDBUF; else sk->sk_sndbuf = val * 2;//val的兩倍大於最小值,則設置成val值的兩倍 /* * Wake up sending tasks if we * upped the value. */ sk->sk_write_space(sk); break; case SO_RCVBUF: /* Don't error on this BSD doesn't and if you think about it this is right. Otherwise apps have to play 'guess the biggest size' games. RCVBUF/SNDBUF are treated in BSD as hints */ if (val > sysctl_rmem_max) val = sysctl_rmem_max; sk->sk_userlocks |= SOCK_RCVBUF_LOCK; /* FIXME: is this lower bound the right one? */ if ((val * 2) < SOCK_MIN_RCVBUF) sk->sk_rcvbuf = SOCK_MIN_RCVBUF; else sk->sk_rcvbuf = val * 2; break;
從上述代碼能夠看出:(1)當設置的值val > 最大值sysctl_wmem_max,則設置爲最大值的2倍:2*sysctl_wmem_max;app
(2)當設置的值的兩倍val*2 > 最小值,則設置成最小值:SOCK_MIN_SNDBUF;socket
(3)當設置的值val < 最大值sysctl_wmem_max,且 val*2 > SOCK_MIN_SNDBUF, 則設置成2*val。tcp
查看linux 手冊:函數
SO_RCVBUF: this
Sets or gets the maximum socket receive buffer in bytes. spa
The kernel doubles this value (to allow space for bookkeeping overhead) when it is set using setsockopt(2), 計算機網絡
and this doubled value is returned by getsockopt(2).
The default value is set by the /proc/sys/net/core/rmem_default file,
and the maximum allowed value is set by the /proc/sys/net/core/rmem_max file.
The minimum (doubled) value for this option is 256.
查看個人主機Linux 2.6.6 :/proc/sys/net/core/rmem_max:
4194304 //4M
查看/proc/sys/net/core/wmem_max:
8388608 //8M
因此,能設置的接收緩衝區的最大值是8M,發送緩衝區的最大值是16M。
疑惑2:爲何要有2倍這樣的一個內核設置呢?個人理解是,用戶在設置這個值的時候,可能只考慮到數據的大小,沒有考慮數據封包的字節開銷。因此將這個值設置成兩倍。
注:overhead,在計算機網絡的幀結構中,除了有用數據之外,還有不少控制信息,這些控制信息用來保證通訊的完成。這些控制信息被稱做系統開銷。
2 tcp緩衝區大小的默認值
創建一個socket,經過getsockopt獲取緩衝區的值以下:
發送緩衝區大小:SNDBufSize = 16384
接收緩衝區大小:RCVBufSize = 87380
疑惑3:linux手冊中,接收緩衝區的默認值保存在/proc/sys/net/core/rmem_default,發送緩衝區保存在/proc/sys/net/core/wmem_default。
[root@cfs_netstorage core]# cat /proc/sys/net/core/rmem_default 1048576 [root@cfs_netstorage core]# cat /proc/sys/net/core/wmem_default 512488
可知,接收緩衝區的默認值是:1048576,1M。發送緩衝區的默認值是:512488,512K。爲何創建一個socket時獲得的默認值是87380、16384???
進一步查閱資料發現, linux下socket緩衝區大小的默認值在/proc虛擬文件系統中有配置。分別在一下兩個文件中:
/proc/sys/net/ipv4/tcp_wmem [root@cfs_netstorage core]# cat /proc/sys/net/ipv4/tcp_wmem 4096 16384 131072 //第一個表示最小值,第二個表示默認值,第三個表示最大值。 /proc/sys/net/ipv4/tcp_rmem [root@cfs_netstorage core]# cat /proc/sys/net/ipv4/tcp_rmem 4096 87380 174760
因而可知,新建socket,選取的默認值都是從這兩個文件中讀取的。能夠經過更改這兩個文件中的值進行調優,可是最可靠的方法仍是在程序中調用setsockopt進行設置。經過setsockopt的設置,能設置的接收緩衝區的最大值是8M,發送緩衝區的最大值是16M(Linux 2.6.6中)。