通訊端與網路程式設計

傾聽與接受(listen and accept)

想像櫃台前的接待員。公司先宣告對來客開放,並擺出一個小小的等候區(listen)。然後接待員一次一位,迎接正在等的人,帶他們到私人房間談話(accept),同時新訪客不斷抵達並等候。listen 與 accept 是伺服器端的兩個步驟,把一個已綁定的通訊端,變成真正能處理進來的 TCP 連線的通訊端。

伺服器呼叫 bind 之後,呼叫 listen(fd, backlog) 把通訊端標記為被動——它不會主動發起連線,只接收連線——並設置一個待處理連線的佇列,大小由 backlog 數字決定。當某個用戶端的三向交握完成,核心把這條完成的連線放進該佇列。伺服器接著呼叫 accept(fd),從佇列取出一條就緒的連線,回傳一個全新的、專屬於那單一用戶端的通訊端。原本的傾聽通訊端維持開啟,繼續收集更多用戶端;新的通訊端才是你讀寫、用來跟這個用戶端對話的對象。accept 會阻塞(等待)直到有連線可用,除非該通訊端是非阻塞的。

為什麼重要:這個「先傾聽再接受」的模式是每台 TCP 伺服器的心跳,而「每個用戶端一個新通訊端」的設計,正是讓一台伺服器能同時服務許多用戶端的關鍵。它也揭露了核心的並行問題:accept 回傳一條連線後,你要在同一個執行緒裡先處理完它才接受下一個(串列、簡單但慢)、為每條連線生出一個行程或執行緒、還是用 I/O 多工把它登記進事件迴圈?backlog 與核心的 accept 佇列在高負載下也很重要——若用戶端連入的速度比你 accept 的速度快,佇列會塞滿,新的連線嘗試會被拒絕或丟棄,這是繁忙伺服器的真實瓶頸。

伺服器迴圈:while true do { conn = accept(listen_fd); handle(conn); }。每次 accept 都為一個用戶端回傳一個新通訊端。最簡單的伺服器會把每個 conn 處理完再繞回去;繁忙的則把 conn 交給執行緒或事件迴圈,好讓下一個 accept 能立即執行。

一個傾聽通訊端維持開啟;accept 生出每個用戶端各自的通訊端。

accept 不會拿傾聽通訊端來傳資料——它為每條連線回傳一個獨立通訊端。傾聽通訊端只負責產生連線;讀寫到錯誤的那個,是初學者常見的臭蟲。

又称
listen()accept()passive open傾聽接受連線