backlog是linux下socket函數之listen的參數,當應用程序調用listen系統調用讓一個socket進入LISTEN狀態時,須要指定一個backlog參數。這個參數常常被描述爲,新鏈接隊列的長度限制。html
因爲TCP創建鏈接須要進行3次握手,一個新鏈接在到達ESTABLISHED狀態能夠被accept系統調用返回給應用程序前,必須通過一箇中間狀態SYN RECEIVED。這意味着,TCP/IP協議棧在實現backlog隊列時,有兩種不一樣的選擇:linux
僅使用一個隊列,隊列規模由listen系統調用backlog參數指定。當協議棧收到一個SYN包時,響應SYN/ACK包而且將鏈接加進該隊列。當相應的ACK響應包收到後,鏈接變爲ESTABLISHED狀態,能夠嚮應用程序返回。這意味着隊列裏的鏈接能夠有兩種不一樣的狀態:SEND RECEIVED和ESTABLISHED。只有後一種鏈接才能被accept系統調用返回給應用程序。bootstrap
使用兩個隊列——SYN隊列(待完成鏈接隊列)和accept隊列(已完成鏈接隊列)。狀態爲SYN RECEIVED的鏈接進入SYN隊列,後續當狀態變動爲ESTABLISHED時移到accept隊列(即收到3次握手中最後一個ACK包)。顧名思義,accept系統調用就只是簡單地從accept隊列消費新鏈接。在這種狀況下,listen系統調用backlog參數決定accept隊列的最大規模。服務器
對於linux操做系統,內核在2.2以後的版本,tcp/ip協議實現了第二種方案,即一個syn隊列,一個accept隊列,syn隊列的長度由系統級別設置,accept隊列的長度能夠由應用級別設置,tcp建連交互流程以下圖所示:網絡
client 端使用 connect() 向 server 端發起鏈接請求(發送 syn 包),此時 client 端的 TCP 的狀態爲 SYN_SENT。併發
server 端在收到 syn 包後,將 TCP 相關信息放到 syn queue(半鏈接隊列)中,同時向 client 發送 syn+ack,server 端 TCP 的狀態爲 SYN_RCVD。socket
client 端收到 server 端的 syn+ack 後,向 server 端發送 ack,此時 client 端的 TCP 的狀態爲 ESTABLISHED。Server 端收到 ack 確認後,從 syn queue 裏將 TCP 信息取出,並放到 accept queue(全鏈接隊列)中,此時 server 端的 TCP 的狀態爲 ESTABLISHED。tcp
系統層面:somaxconn參數,能夠經過編輯/proc/sys/net/core/somaxconn的值進行設置函數
應用層面:對於netty服務端來講,經過serverbootstrap的option進行設置,即option((ChannelOption.SO_BACKLOG,number),number即爲要設置的大小,類型爲int高併發
backlog最終的取值爲兩者中的最小值,即min(backlog,somaxconn),在服務啓動以後,咱們能夠經過,ss -tnlp進行查看,以下圖所示:
對於backlog隊列的使用狀況,咱們能夠經過netstat進行查詢,以下圖所示:
當tcp_abort_on_overflow=0,直接丟棄該ACK,經過tcpdump抓包,能夠看到以下的交互流程
當tcp_abort_on_overflow=1,發送RST通知client,client會報connection reset by peer
抓包查看其流程以下所示:
經過ss -tnlp 查詢監聽端口全鏈接隊列的使用狀況。
經過netstat查詢出鏈接狀態處於established、但未關聯進程號的鏈接,此鏈接對應着源端口以及目標端口,此鏈接的源端口就是咱們應用程序監聽的端口,即出現backlog隊列溢出的端口號。