Program received signal SIGPIPE, Broken pipe

來源:互聯網
上載者:User

轉自:http://www.diybl.com/course/3_program/c++/cppjs/20090831/173152.html

我寫了一個伺服器程式, 在Windows下在cygwin環境編譯後執行, 然後用C#寫了多線程用戶端進行壓力測試. 程式一直運行正常. 但當在Linux下測試時, 總是莫名退出. 最後跟蹤到是write調用導致退出. 用gdb執行程式, 退出時提示"Broken pipe".

最後問題確定為, 對一個對端已經關閉的socket調用兩次write, 第二次將會產生SIGPIPE訊號, 該訊號預設結束進程.
具體的分析可以結合TCP的"四次握手"關閉. TCP是全雙工系統的通道, 可以看作兩條單工通道, TCP串連兩端的兩個端點各負責一條. 當對端調用close時, 雖然本意是關閉整個兩條通道, 但本端只是收到FIN包. 按照TCP協議的語義, 表示對端只是關閉了其所負責的那一條單工通道, 仍然可以繼續接收資料. 也就是說, 因為TCP協議的限制, 一個端點無法獲知對端的socket是調用了close還是shutdown.

來自: UNPv1
對一個已經收到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毫秒.

忽略SIGPIPE訊號的方法

http://hi.baidu.com/greathongjian/blog/item/2f695643091885139213c65a.html

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異常
hi.baidu.com/ailacy/blog/item/a7eb65f8b8b55707d8f9fdd5.html

http://bbs2.chinaunix.net/viewthread.php?tid=985166&extra=&page=1

在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");
}
#endif
當然,這隻是多種方法之一~
根據賴半仙的使用經驗,只要在main函數一開始就寫入上面這段代碼,就能屏蔽掉pthread線程中的SIGPIPE

[linux] SIGPIPE訊號及其處理

http://hi.baidu.com/mckeyzhang/blog/item/d647f26034eee542eaf8f823.html

在linux下寫socket的程式的時候,如果嘗試send到一個disconnected socket上,就會讓底層拋出一個SIGPIPE訊號。
這個訊號的預設處理方法是退出進程,大多數時候這都不是我們期望的。因此我們需要重載這個訊號的處理方法。調用以下代碼,即可安全的屏蔽SIGPIPE:
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, 0 );
//======================================================================
SIGPIPE
From Wikipedia, the free encyclopedia
Jump to: navigation, search
SIGPIPE
Description Write on a pipe with no one to read it
Default action Abnormal termination of the process
SA_SIGINFOmacros
one
On POSIX-compliant platforms, SIGPIPE is the signal raised when a computer program attempts to write to apipe without a process connected to the other end. The symbolic constant for SIGPIPE is defined in the header file signal.h. Symbolic signal names are used
because signal numbers can vary across platforms.
Etymology
SIG is a common prefix for signal names. PIPE refers to the Unix pipe.
Description
Unix supports the principle of piping, which allows processes to send data to other processes without the need for creating temporary files. When a pipe is broken, the process writing to it is sent the SIGPIPE signal. The default reaction to this signal for
a process is to terminate.
A simple example of piping is the following.
ps l | head
This command, when run on a Unix-like machine (including Linux), returns a list of processes, limited to ten lines.
ps l returns a list of all processes (including those of other users).
head selects the first ten lines.
When ps has written ten lines, head has received all it needs and exits. ps will receive a SIGPIPE when it tries to write the remaining lines, causing it to terminate as well: It is no use writing data that no one will use. It is also possible that the reading
process terminates while reading the data. This will also cause SIGPIPE to be sent to the writing process.
One can ignore SIGPIPE (using, for example, the signal system call). In this case, all system calls that would cause SIGPIPE to be sent will return -1 and set errno to EPIPE.

Uinx 下 Broken pipe 問題
www.javaeye.com/topic/456975#
前段時間在處理延時函數時遇到過 "Alarm clock" 訊號問題(見我的 "Unix C 延時函數小結")。現在測試中還遇到了 "Broken pipe" 訊號問題,同樣產生這個訊號程式就中止了。

我的程式產生這個訊號的原因是:
client端通過 pipe 發送資訊到server端後,就關閉client端, 這時server端,返回資訊給 client 端時就產生Broken pipe 訊號了。

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

系統裡邊定義了三種處理方法:
1)SIG_DFL
2)SIG_IGN
3)SIG_ERR

項目中我調用了 signal(SIGALRM, SIG_IGN) 和 signal(SIGPIPE, SIG_IGN), 這樣產生 SIGALAM 和 SIGPIPE 訊號時就不會中止程式,直接把這個訊號忽略掉。

自訂處理方法:
C代碼
void signal_handle(ing signo)
{
//do something;
}

int main()
{
signal(SIGPIPE, signal_handle);
......
}
聲明:JavaEye文章著作權屬於作者,受法律保護。沒有作者書面許可不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.