跳至內容

Linux SIGPIPE信號

更新時間
连续6年不跑路的安全速度最适合国人VPN
连续6年不跑路的安全速度最适合国人VPN

在 tcp 通信雙方中,爲了描述方便,以下將通信雙方用 a 和 b 代替。

根據TCP協議規定,如果A關閉連接後B繼續發送數據,B會收到A的RST響應。若B繼續發送數據,系統會發出SIGPIPE信號告知連接已斷開,停止發送。

系統對 SIGPIPE 信號的默認處理行爲是讓 B 進程退出。

操作系統對 SIGPIPE 信號的這種默認處理行爲非常不友好,讓我們來分析一下。

TCP通信是全雙工信道,相當於兩條單工信道,連接兩端各負責一條。

當對端“關閉”時, 雖然本意是關閉整個兩條信道,但本端只是收到 FIN 包。

根據TCP協議的規定,當一端關閉其負責的單向通道時,仍可接收數據但不再發送數據。

也就是說,因爲 TCP 協議的限制,通信一方無法獲知對端的 socket 是調用了 close 還是 shutdown。

int shutdown(int socket, int how);
登錄後複製

shutdown 函數的參數 how 可以設置爲關閉 SHUT_RD、SHUT_WR 或 SHUT_RDWR 用於表示關閉收、發單個通道或者同時關閉收發通道。

對一個已經收到 FIN 包的 socket 調用 read/recv 方法, 如果接收緩衝已空,則返回 0,這就是常說的表示連接關閉。但第一次對其調用 write/send 方法時,如果發送緩衝沒問題,會返回正確寫入(即 write/send 函數返回值大於 0),但發送的報文會導致對端回應 RST 報文。因爲上一次程序調用 write/send 是正常的,再次嘗試調用 write/send 函數時因產生 SIGPIPE 信號導致進程退出。

這種默認行爲對於我們開發程序,尤其是對於後端服務,需要同時對許多客戶端服務,不能因爲與某一個客戶端的連接出問題了而導致整個進程退出不能繼續爲其他客戶端服務。

爲了避免這種現象出現, 可以捕獲 SIGPIPE 信號並對其進行處理或者忽略該信號, 忽略該信號代碼如下:

signal(SIGPIPE, SIG_IGN);
登錄後複製

這樣設置後,第二次調用 write/send 方法時,會返回 -1,同時 errno 錯誤碼被置爲 SIGPIPE,程序便能知道對端已經關閉。

以上就是Linux SIGPIPE信號的詳細內容,更多請關注本站其它相關文章!

更新時間

發表留言

請注意,留言須先通過審核才能發佈。