1. 程式人生 > >Linux下send函式 Broken pipe錯誤的解決方法

Linux下send函式 Broken pipe錯誤的解決方法

在linux下寫socket的程式的時候,如果嘗試send到一個disconnected socket上,就會讓底層丟擲一個SIGPIPE訊號。

client端通過 pipe 傳送資訊到server端後,就關閉client端, 這時server端,返回資訊給 client 端時就產生Broken pipe 訊號了。

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

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

為了避免程序退出, 可以捕獲SIGPIPE訊號, 或者忽略它, 
給它設定SIG_IGN訊號處理函式:

signal(SIGPIPE, SIG_IGN);

這樣, 第二次呼叫write方法時, 會返回-1, 同時errno置為SIGPIPE. 
程式便能知道對端已經關閉.

PS: Linux下的SIGALRM似乎會每1秒鐘往後偏移1毫秒, 
但Windows下經過測試完全準時, 不差1毫秒.

標頭檔案 #include <signal.h>

struct sigaction sa;
sa.sa_handler = SIG_IGN;//設定接受到指定訊號後的動作為忽略
sa.sa_flags = 0;
if (sigemptyset(&sa.sa_mask) == -1 || //初始化訊號集為空
sigaction(SIGPIPE, &sa, 0) == -1) { //遮蔽SIGPIPE訊號
perror("failed to ignore SIGPIPE; sigaction");
exit(EXIT_FAILURE);
}

pthread執行緒裡如何遮蔽SIGPIPE異常

在pthread中,可能會遇到Program received signal SIGPIPE, Broken 
pipe的問題,解決方法是每一個執行緒啟動之前時,先執行下面程式碼:

#ifndef WIN32
sigset_t signal_mask;
sigemptyset (&signal_mask);
sigaddset (&signal_mask, SIGPIPE);
int rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
if (rc != 0) {
printf("block sigpipe error\n");
}