在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");
}
linux訊號集合——用來描述訊號的 sigset_t typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
標頭檔及訊號處理函數:
標頭檔
#include <signal.h>
sigemptyset(sigset_t *set)初始化由set指定的訊號集,訊號集裡面的所有訊號被清空;
sigfillset(sigset_t *set)調用該函數後,set指向的訊號集中將包含linux支援的64種訊號;
sigaddset(sigset_t *set, int signum)在set指向的訊號集中加入signum訊號;
sigdelset(sigset_t *set, int signum)在set指向的訊號集中刪除signum訊號;
sigismember(const sigset_t *set, int signum)判定訊號signum是否在set指向的訊號集中
註:這裡面的方法好像不管用!