Linux下高性能网络编程中的几个TCP/IP选项_SO_REUSEADDR、SO_RECVBUF、SO_SNDBUF、SO_KEEPALIVE、SO_LINGER、TCP_CORK、TCP_NODE
? ? ? ? 最近在新的平臺上測試程序,以前一些沒有注意到的問題都成為了性能瓶頸,通過設置一些TCP/IP選項能夠解決一部分問題,當然根本的解決方法是重構(gòu)代碼,重新設計服務器框架。先列出幾個TCP/IP選項:
選項
man 7 socket:
SO_REUSEADDR
SO_RECVBUF/SO_SNDBUF
SO_KEEPALIVE
SO_LINGER
man 7 tcp:
TCP_CORK
TCP_NODELAY
TCP_DEFER_ACCEPT
TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
SO_REUSEADDR
man 命令的?領(lǐng)域?名稱 說明
1 用戶命令, 可由任何人啟動的。
2 系統(tǒng)調(diào)用, 即由內(nèi)核提供的函數(shù)。
3 例程, 即庫函數(shù)。
4 設備, 即/dev目錄下的特殊文件。
5 文件格式描述, 例如/etc/passwd。
6 游戲, 不用解釋啦!
7 雜項, 例如宏命令包、慣例等。
8 系統(tǒng)管理員工具, 只能由root啟動。
9 其他(Linux特定的), 用來存放內(nèi)核例行程序的文檔。
SO_REUSEADDR選項:
在服務器程序中,SO_REUSEADDR socket選項通常在調(diào)用bind()之前被設置。
SO_REUSEADDR可以用在以下四種情況下:?
(摘自《Unix網(wǎng)絡編程》卷一,即UNPv1)
1、當有一個有相同本地地址和端口的socket1處于TIME_WAIT狀態(tài)時,而你啟動的程序的socket2要占用該地址和端口,你的程序就要用到該選項。?
2、SO_REUSEADDR允許同一port上啟動同一服務器的多個實例(多個進程)。但每個實例綁定的IP地址是不能相同的。在有多塊網(wǎng)卡或用IP Alias技術(shù)的機器可以測試這種情況。?
3、SO_REUSEADDR允許單個進程綁定相同的端口到多個socket上,但每個socket綁定的ip地址不同。這和2很相似,區(qū)別請看UNPv1。?
4、SO_REUSEADDR允許完全相同的地址和端口的重復綁定。但這只用于UDP的多播,不用于TCP。
TCP_NODELAY/TCP_CHORK選項:
TCP_NODELAY/TCP_CHORK
TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在這里的含義是采用Nagle算法把較小的包組裝為更大的幀。TCP_NODELAY和TCP_CORK都禁掉了Nagle算法,只不過他們的行為不同而已。
TCP_NODELAY 不使用Nagle算法,不會將小包進行拼接成大包再進行發(fā)送,直接將小包發(fā)送出去,會使得小包時候用戶體驗非常好。
Nagle算法參見自己的博客:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201231214038740/
當在傳送大量數(shù)據(jù)的時候,為了提高TCP發(fā)送效率,可以設置TCP_CORK,CORK顧名思義,就是"塞子"的意思,它會盡量在每次發(fā)送最大的數(shù)據(jù)量。當設置了TCP_CORK后,會有阻塞200ms,當阻塞時間過后,數(shù)據(jù)就會自動傳送。
詳細的資料可以查看參考文獻5。
SO_LINGER選項:
SO_LINGER
linger,顧名思義是延遲延緩的意思,這里是延緩面向連接的socket的close操作。
默認,close立即返回,但是當發(fā)送緩沖區(qū)中還有一部分數(shù)據(jù)的時候,系統(tǒng)將會嘗試將數(shù)據(jù)發(fā)送給對端。SO_LINGER可以改變close的行為。
控制SO_LINGER通過下面一個結(jié)構(gòu):
struct linger
{
????? int l_onoff; /*0=off, nonzero=on*/
????? int l_linger; /*linger time, POSIX specifies units as seconds*/
};
通過結(jié)構(gòu)體中成員的不同賦值,可以表現(xiàn)為下面幾種情況:
1. l_onoff設置為0,選項被關(guān)閉。l_linger值被忽略,就是上面的默認情形,close立即返回。
2. l_onoff設置為非0,l_linger被設置為0,則close()不被阻塞立即執(zhí)行,丟棄socket發(fā)送緩沖區(qū)中的數(shù)據(jù),并向?qū)Χ税l(fā)送一個RST報文。
????這種關(guān)閉方式稱為“強制”或“失效”關(guān)閉。
3. l_onoff設置為非0,l_linger被設置為非0,則close()調(diào)用阻塞進程,直到所剩數(shù)據(jù)發(fā)送完畢或超時。
????這種關(guān)閉稱為“優(yōu)雅的”關(guān)閉。
注意:
?????? 這個選項需要謹慎使用,尤其是強制式關(guān)閉,會丟失服務器發(fā)給客戶端的最后一部分數(shù)據(jù)。UNP中:
The TIME_WAIT state is our friend and is there to help us(i.e., to let the old duplicate segments expire in the network).
?
TCP_DEFER_ACCEPT選項:
TCP_DEFER_ACCEPT
defer accept,從字面上理解是推遲accept,實際上是當接收到第一個數(shù)據(jù)之后,才會創(chuàng)建連接,三次握手完成,連接還沒有建立。
對于像HTTP等非交互式的服務器,這個很有意義,可以用來防御空連接攻擊(只是建立連接,但是不發(fā)送任何數(shù)據(jù))。
使用方法如下:
| val = 5; setsockopt(srv_socket->fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)) ; |
里面 val 的單位是秒,注意如果打開這個功能,kernel 在 val 秒之內(nèi)還沒有收到數(shù)據(jù),不會繼續(xù)喚醒進程,而是直接丟棄連接。如果服務器設置TCP_DEFER_ACCEPT選項后,服務器受到一個CONNECT請求后,三次握手之后,新的socket狀態(tài)依然為SYN_RECV,而不是ESTABLISHED,操作系統(tǒng)不會Accept。
由于設置TCP_DEFER_ACCEPT選項之后,三次握手后狀態(tài)沒有達到ESTABLISHED,而是SYN_RECV。這個時候,如果客戶端一直沒有發(fā)送"數(shù)據(jù)"報文,服務器將重傳SYN/ACK報文,重傳次數(shù)受net.ipv4.tcp_synack_retries參數(shù)控制,達到重傳次數(shù)之后,才會再次進行setsockopt中設置的超時值,因此會出現(xiàn)SYN_RECV生存時間比設置值大一些的情況。
關(guān)于SYN_RECV狀態(tài)可以查看參考文獻7。
?
SO_KEEPALIVE選項:
SO_KEEPALIVE/TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
??????? 如果一方已經(jīng)關(guān)閉或異常終止連接,而另一方卻不知道,我們將這樣的TCP連接稱為半打開的。
??????? TCP通過?;疃〞r器(KeepAlive)來檢測半打開連接。
???????? 在高并發(fā)的網(wǎng)絡服務器中,經(jīng)常會出現(xiàn)漏掉socket的情況,對應的結(jié)果有一種情況就是出現(xiàn)大量的CLOSE_WAIT狀態(tài)的連接。這個時候,可以通過設置KEEPALIVE選項來解決這個問題,當然還有其他的方法可以解決這個問題,詳細的情況可以查看參考資料8。
使用方法如下:
| //Setting For KeepAlive int keepalive = 1; setsockopt(incomingsock,SOL_SOCKET,SO_KEEPALIVE,(void*)(&keepalive),(socklen_t)sizeof(keepalive)); int keepalive_time = 30; setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPIDLE,(void*)(&keepalive_time),(socklen_t)sizeof(keepalive_time)); int keepalive_intvl = 3; setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPINTVL,(void*)(&keepalive_intvl),(socklen_t)sizeof(keepalive_intvl)); int keepalive_probes= 3; setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPCNT,(void*)(&keepalive_probes),(socklen_t)sizeof(keepalive_probes)); |
?????? 設置SO_KEEPALIVE選項來開啟KEEPALIVE,然后通過TCP_KEEPIDLE、TCP_KEEPINTVL和TCP_KEEPCNT設置keepalive的開始時間、間隔、次數(shù)等參數(shù)。
??????? 當然,也可以通過設置/proc/sys/net/ipv4/tcp_keepalive_time、tcp_keepalive_intvl和tcp_keepalive_probes等內(nèi)核參數(shù)來達到目的,但是這樣的話,會影響所有的socket,因此建議使用setsockopt設置
總結(jié)
以上是生活随笔為你收集整理的Linux下高性能网络编程中的几个TCP/IP选项_SO_REUSEADDR、SO_RECVBUF、SO_SNDBUF、SO_KEEPALIVE、SO_LINGER、TCP_CORK、TCP_NODE的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 加速群辉Docker镜像下载速度的方法
- 下一篇: Linux Kconfig及Makefi