TCP socket 服務開發的4個步驟 socket->bind->listen->accept
調用listen函數時,有一個backlog參數.html
int listen(int sockfd, int backlog);linux
FreeBSD 和 Linux的實現有些不一樣, 本文討論Linux.
在Linux中backlog表示已完成(ESTABLISHED)且未accept的隊列大小.git
TCP鏈接建立過程
服務器收到客戶端SYN包,發送SYN+ACK包後,在內存建立一個狀態爲SYN_RCVD 的鏈接,放入未完成隊列,這個隊列的大小可經過/proc/sys/net/ipv4/tcp_max_syn_backlog設置.github
服務器收到客戶端的ACK包後,該鏈接的狀態由SYN_RCVD改成ESTABLISHED,並移到已完成隊列.
服務器程序調用accept後,該鏈接移除已完成隊列, 由內核交給程序控制.服務器
TCP 三次握手在應用程序accept以前由內核完成. 應用程序調用accept只是獲取已經完成的鏈接.cookie
已完成隊列滿後
一般未完成隊列的長度大於已完成隊列.
已完成隊列滿後, 當服務器收到來自客戶端的ACK包時
若是 /proc/sys/net/ipv4/tcp_abort_on_overflow 設爲 1, 直接回RST包,結束鏈接.
不然忽視ACK包.
內核有定時器管理未完成隊列,對於因爲網絡緣由沒收到ACK包或是收到ACK包後被忽視的SYN_RCVD鏈接重發SYN+ACK包, 最多重發次數由/proc/sys/net/ipv4/tcp_synack_retries 設定.網絡
backlog 即上述已完成隊列的大小, 這個設置是個參考值,不是精確值. 內核會作些調整, 大於/proc/sys/net/core/somaxconn, 則取somaxconn的值socket
未完成隊列滿後
若是啓用syncookies (net.ipv4.tcp_syncookies = 1),新的鏈接不進入未完成隊列,不受影響.
不然,服務器不在接受新的鏈接.tcp
SYN 洪水攻擊(syn flood attack)
經過僞造IP向服務器發送SYN包,塞滿服務器的未完成隊列,服務器發送SYN+ACK包 沒回復,反覆SYN+ACK包,使服務器不可用.函數
啓用syncookies 是簡單有效的抵禦措施.
啓用syncookies,僅未完成隊列滿後才生效.
參考:
http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html
http://blog.dubbelboer.com/2012/04/09/syn-cookies.html
http://blog.csdn.net/justlinux2010/article/details/8604676