signal(SIGPIPE, SIG_IGN)解析

我寫了一個服務器程序,在Linux下測試,而後用C++寫了客戶端用千萬級別數量的短連接進行壓力測試.  可是服務器老是莫名退出,沒有core文件.linux

最後問題肯定爲, 對一個對端已經關閉的socket調用兩次write, 第二次將會生成SIGPIPE信號, 該信號默認結束進程.安全

具體的分析能夠結合TCP的"四次握手"關閉. TCP是全雙工的信道, 能夠看做兩條單工信道, TCP鏈接兩端的兩個端點各負責一條. 當對端調用close時, 雖然本意是關閉整個兩條信道, 但本端只是收到FIN包. 按照TCP協議的語義, 表示對端只是關閉了其所負責的那一條單工信道, 仍然能夠繼續接收數據. 也就是說, 由於TCP協議的限制, 一個端點沒法獲知對端的socket是調用了close仍是shutdown.服務器

對一個已經收到FIN包的socket調用read方法, 若是接收緩衝已空, 則返回0, 這就是常說的表示鏈接關閉. 但第一次對其調用write方法時, 若是發送緩衝沒問題, 會返回正確寫入(發送). 但發送的報文會致使對端發送RST報文, 由於對端的socket已經調用了close, 徹底關閉, 既不發送, 也不接收數據. 因此, 第二次調用write方法(假設在收到RST以後), 會生成SIGPIPE信號, 致使進程退出.socket

爲了不進程退出, 能夠捕獲SIGPIPE信號, 或者忽略它, 給它設置SIG_IGN信號處理函數:函數

signal(SIGPIPESIG_IGN);測試

這樣, 第二次調用write方法時, 會返回-1, 同時errno置爲SIGPIPE. 程序便能知道對端已經關閉.線程

 

linux下寫socket的程序的時候,若是嘗試send到一個disconnected socket上,就會讓底層拋出一個SIGPIPE信號。
這個信號的缺省處理方法是退出進程,大多數時候這都不是咱們指望的。所以咱們須要重載這個信號的處理方法。調用如下代碼,便可安全的屏蔽SIGPIPEserver

signal (SIGPIPE, SIG_IGN);進程

個人程序產生這個信號的緣由是: 
client端經過 pipe 發送信息到server端後,就關閉client端, 這時server端,返回信息給 client 端時就產生Broken pipe 信號了,服務器就會被系統結束了。ip

 

對於產生信號,咱們能夠在產生信號前利用方法 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(SIGPIPESIG_IGN), 這樣產生  SIGPIPE 信號時就不會停止程序,直接把這個信號忽略掉。

服務器採用了fork的話,要收集垃圾進程,防止殭屍進程的產生,能夠這樣處理: 
  signal(SIGCHLD,SIG_IGN); 交給系統init去回收。 
  這裏子進程就不會產生殭屍進程了。 
相關文章
相關標籤/搜索