一、問題回顧
面試的時候被問到的問題,原問題是:
1:寫一下socket網絡編程服務端和客戶端常用的函數。
2:如果服務端在listen之後沒有accept,那客戶端的connect會返回嗎?爲什麼?
3:此時調用send發數據會怎麼樣?
在看下面答案之前,推薦閱讀:
深入探索 Linux listen() 函數 backlog 的含義
Socket accept queue is full 但是一個連接需要從SYN->ACCEPT
下面是我對這個問題實驗整理的結果:
情況 | ESTABLISHED 隊列沒有滿 | SYN_RECV隊列沒有滿 | SYN_RECV 隊列滿了 |
---|---|---|---|
connect返回情況 | connect 正常返回 | connect 正常返回 | connect返回timeout錯誤 |
send寫數據 | 完全正常寫,並且數據會被服務器回覆ack確認。之後如果accept,可以read出數據。 | 不能正常發送,會不斷觸發重傳,但是數據不會被確認。 | 這時候的socket是完全disconnect的,send給disconnect的socket寫數據,觸發SIGPIPE信號,默認殺死本進程。 |
二、總結
有關connect
函數返回錯誤的情況,常見的有下面三種:
- 返回
TIMEOUT
,即SYN_RECV
隊列都滿了,對於客戶端發來的三次握手第一次的SYN
都沒有辦法響應,這時候TCP
會隔6s
,24s
重發,直到75s
,如果還是沒有被接受,最後返回TIMEOUT
錯誤。 - 返回
ECONNREFUSED
錯誤,表示服務器主機沒有在相應的端口開啓監聽。 - 返回
EHOSTUNREACH
或ENETUNREACH
,表示在某個中間路由節點返回了ICMP
錯誤,這個錯誤被內核先保存,之後繼續按照6s
,24s
重發,直到75s
,如果還是沒有響應,就返回EHOSTUNREACH
或ENETUNREACH
錯誤。
我那個問題只涉及了TIMEOUT
的情況,沒有後兩種,另外:
connect
什麼時候正常返回?其實是客戶端收到服務器三次握手第二次返回的
SYN+ACK
之後,自己進入了ESTABLISHED
狀態(TCP狀態轉換圖),這時候connect
就會正常返回了。