水平有限嫉沽,如有紕漏呀潭,敬請(qǐng)指正昔逗!
TCP服務(wù)
創(chuàng)建TCP服務(wù)的四個(gè)基本步驟:
- socket – 創(chuàng)建socket套接字降传。
- bind – 綁定要監(jiān)聽(tīng)的IP地址。
- listen – 開(kāi)始監(jiān)聽(tīng)客戶端連接請(qǐng)求勾怒。
- accept – 獲取TCP握手成功的連接婆排。
其中,第3步控硼,開(kāi)始監(jiān)聽(tīng)客戶端的連接請(qǐng)求時(shí)泽论,需要指定一個(gè)backlog的參數(shù):
int listen(int sockfd, int backlog);
這個(gè)backlog參數(shù)有什么作用呢艾少?不同的操作系統(tǒng)可能有不同的意義卡乾,本文只討論backlog參數(shù)在Linux環(huán)境下的作用。
TCP連接
建立TCP連接有一個(gè)“三次握手”的過(guò)程:
- 客戶端向服務(wù)端發(fā)起連接請(qǐng)求缚够,發(fā)送SYN包幔妨。
- 服務(wù)端收到客戶端的SYN包后向客戶端響應(yīng)ACK+SYN包,同時(shí)在內(nèi)存中建立一個(gè)狀態(tài)為SYN-RECEIVED的連接谍椅,將連接放進(jìn)incomplete connection queue误堡。
- 客戶端收到服務(wù)端的回包后,向服務(wù)發(fā)送ACK包雏吭。服務(wù)端收到ACK后锁施,TCP連接進(jìn)入ESTABLISHED狀態(tài),將連接放進(jìn)complete connection queue杖们,等待應(yīng)用程序進(jìn)行accept悉抵。
- 在Linux內(nèi)核中,步驟2的未完成TCP連接由一個(gè)incomplete connection queue維護(hù)摘完,其最大長(zhǎng)度為
/proc/sys/net/ipv4/tcp_max_syn_backlog
姥饰。 - 步驟3的已完成TCP連接由一個(gè)complete connection queue維護(hù),其最大長(zhǎng)度為listen函數(shù)的參數(shù)
backlog
孝治。 - 畫(huà)個(gè)簡(jiǎn)圖列粪,總結(jié)一下上面的內(nèi)容:
當(dāng)隊(duì)列滿了……
SYN cookie
SYN cookie是一種用于對(duì)抗SYN flood攻擊的技術(shù)审磁,可以避免在incomplete connection queue被填滿時(shí)無(wú)法建立新的TCP連接。對(duì)于使用SYN Cookie的服務(wù)來(lái)說(shuō)岂座, 當(dāng)incomplete connection queue被填滿時(shí)态蒂,服務(wù)器會(huì)表現(xiàn)得像SYN隊(duì)列擴(kuò)大了一樣。對(duì)于隊(duì)列填滿后的新TCP連接费什,服務(wù)器會(huì)返回適當(dāng)?shù)腟YN+ACK響應(yīng)包吃媒,但會(huì)丟棄對(duì)應(yīng)的SYN隊(duì)列條目(因?yàn)殛?duì)列已經(jīng)滿了)。如果服務(wù)器收到客戶端隨后的ACK響應(yīng)吕喘,服務(wù)器能夠使用編碼在 TCP 序號(hào)內(nèi)的信息重構(gòu) SYN 隊(duì)列條目赘那。
incomplete connection queue
- 關(guān)閉syncookies(net.ipv4.tcp_syncookies = 0):當(dāng)隊(duì)列滿時(shí),不在接受新的連接氯质。
- 開(kāi)啟syncookies(net.ipv4.tcp_syncookies = 1):當(dāng)隊(duì)列滿時(shí)募舟,不受影響。
complete connection queue
當(dāng)complete connection queue滿了闻察,已經(jīng)完成三次握手的TCP連接該怎么辦拱礁?
內(nèi)核收到客戶端的ACK包后,會(huì)執(zhí)行函數(shù)tcp_check_req辕漂,進(jìn)行一些檢查后呢灶,準(zhǔn)備把TCP連接放到complete connection queue中:
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, req, &own_req);
if (!child)
goto listen_overflow;
對(duì)于ipv4來(lái)說(shuō),執(zhí)行的是函數(shù)tcp_v4_syn_recv_sock
if (sk_acceptq_is_full(sk))
goto exit_overflow;
exit_overflow處的代碼會(huì)進(jìn)行一些清理工作钉嘹,然后返回NULL鸯乃,最后執(zhí)行l(wèi)isten_overflow處的代碼:
listen_overflow:
if (!sysctl_tcp_abort_on_overflow) {
inet_rsk(req)->acked = 1;
return NULL;
}
- 當(dāng)
sysctl_tcp_abort_on_overflow
為0時(shí),Linux內(nèi)核只丟棄客戶端的ACK包跋涣,然后“什么都不做”缨睡。 - 當(dāng)
sysctl_tcp_abort_on_overflow
非0時(shí),Linux內(nèi)核會(huì)返回RST包陈辱,reset TCP連接奖年。 -
sysctl_tcp_abort_on_overflow
對(duì)應(yīng)的設(shè)置是/proc/sys/net/ipv4/tcp_abort_on_overflow
。
(完)