關於SIGPIPE訊號

2021-07-03 08:55:15 字數 2003 閱讀 4653

我寫了乙個伺服器程式,在

linux下測試,然後用c++寫了客戶端用千萬級別數量的短鏈結進行壓力測試. 

但是伺服器總是莫名退出,沒有core檔案.

最後問題確定為, 對乙個對端已經關閉的socket呼叫兩次write, 第二次將會生成

sigpipe訊號, 該訊號預設結束程序.

具體的分析可以結合tcp的"四次握手"關閉. tcp是全雙工的通道, 可以看作兩條單工通道, tcp連線兩端的兩個端點各負責一條. 當對端呼叫close時, 雖然本意是關閉整個兩條通道, 但本端只是收到fin包. 按照tcp協議的語義, 表示對端只是關閉了其所負責的那一條單工通道, 仍然可以繼續接收資料. 也就是說, 因為tcp協議的限制, 乙個端點無法獲知對端的socket是呼叫了close還是shutdown.

對乙個已經收到fin包的socket呼叫read方法, 如果接收緩衝已空, 則返回0, 這就是常說的表示連線關閉. 但第一次對其呼叫write方法時, 如果傳送緩衝沒問題, 會返回正確寫入(傳送). 但傳送的報文會導致對端傳送rst報文, 因為對端的socket已經呼叫了close, 完全關閉, 既不傳送, 也不接收資料. 所以, 第二次呼叫write方法(假設在收到rst之後), 會生成

sigpipe訊號, 導致程序退出.

為了避免程序退出, 可以捕獲

sigpipe訊號, 或者忽略它, 給它設定

sig_ign訊號處理函式:

signal(

sigpipe

sig_ign);

這樣, 第二次呼叫write方法時, 會返回-1, 同時errno置為

epipe

. 程式便能知道對端已經關閉.

linux下寫socket的程式的時候,如果嘗試send到乙個disconnected socket上,就會讓底層丟擲乙個

sigpipe訊號。

這個訊號的預設處理方法是退出程序,大多數時候這都不是我們期望的。因此我們需要過載這個訊號的處理方法。呼叫以下**,即可安全的遮蔽

sigpipe

signal (sigpipe, sig_ign);

我的程式產生這個訊號的原因是: 

client端通過 pipe 傳送資訊到server端後,就關閉client端, 這時server端,返回資訊給 client 端時就產生broken pipe 訊號了,伺服器就會被系統結束了。

對於產生訊號,我們可以在產生訊號前利用方法 

signal(int signum, sighandler_t handler) 設定訊號的處理。如果沒有呼叫此方法,系統就會呼叫預設處理方法:中止程式,顯示提示資訊(就是我們經常遇到的問題)。我們可以呼叫系統的處理方法,也可以自定義處理方法。 

系統裡邊定義了三種處理方法: 

(1)sig_dfl訊號專用的預設動作:

(a)如果預設動作是暫停執行緒,則該執行緒的執行被暫時掛起。當執行緒暫停期間,傳送給執行緒的任何附加訊號都不交付,直到該執行緒開始執行,但是sigkill除外。

(b)把掛起訊號的訊號動作設定成sig_dfl,且其預設動作是忽略訊號 (sigchld)。

(2)sig_ign忽略訊號

(a)該訊號的交付對執行緒沒有影響

(b)系統不允許把sigkill或sigtop訊號的動作設定為sig_dfl

3)sig_err 

專案中我呼叫了signal(sigpipe,sig_ign), 這樣產生sigpipe訊號時就不會中止程式,直接把這個訊號忽略掉。

關於SIGPIPE訊號

我寫了乙個伺服器程式,在linux下測試,然後用c 寫了客戶端用千萬級別數量的短鏈結進行壓力測試.但是伺服器總是莫名退出,沒有core檔案.最後問題確定為,對乙個對端已經關閉的socket呼叫兩次write,第二次將會生成sigpipe訊號,該訊號預設結束程序.具體的分析可以結合tcp的 四次握手 ...

關於SIGPIPE訊號

我寫了乙個伺服器程式,在linux下測試,然後用c 寫了客戶端用千萬級別數量的短鏈結進行壓力測試.但是伺服器總是莫名退出,沒有core檔案.最後問題確定為,對乙個對端已經關閉的socket呼叫兩次write,第二次將會生成sigpipe訊號,該訊號預設結束程序.具體的分析可以結合tcp的 四次揮手 ...

關於SIGPIPE訊號

我寫了乙個伺服器程式,在linux下測試,然後用c 寫了客戶端用千萬級別數量的短鏈結進行壓力測試.但是伺服器總是莫名退出,沒有core檔案.最後問題確定為,對乙個對端已經關閉的socket呼叫兩次write,第二次將會生成sigpipe訊號,該訊號預設結束程序.具體的分析可以結合tcp的 四次握手 ...