tcp斷開導致進程退出

問題出現的情景及表現

最近寫一個網絡應用,裏面有TCP類型socket通信。因爲需要這同一份代碼在Linux和sylixos上都能編譯運行,所以要採用POSIX標準進行編寫。

開始在兩個系統下運行都是正常的,客戶端每秒向服務端發送數據並得到應答。後來修改客戶端代碼,希望在客戶端發現連接異常或斷開時能間隔10秒再從新連接,這樣客戶端主體其實是個無限循環,不應該會有退出。

測試發現當運行中如果直接關閉了服務端程序,sylixos下客戶端會打印異常狀態並休眠10秒後在次嘗試連接,而Linux下客戶端卻是直接退出進程。

關鍵代碼如下,tcpClientPthread是一個線程執行函數,裏面是一個while(1)無線循環,tcpClient函數中進行TCP客戶端操作,預想的是運行中檢查到錯誤或服務端斷開此函數才退出,然後休眠10秒再次嘗試連接通信。

static  void   *tcpClientPthread (void * pvArg)
{
    ARG_ST  *parg = (ARG_ST  *)pvArg;

    while (1) {
        tcpClient(parg);
        sleep(10);
    }

    return  (NULL);
}

sylixos下客戶端在服務端主動斷開時表現的情況和預期一致,服務端斷開時會立即輸出錯誤信息,並在等待10秒後再次嘗試連接。如下:
在這裏插入圖片描述

Linux下客戶端在服務端主動斷開時表現的情況和預期不一致,客戶端進程直接退出,也沒有任何錯誤信息輸出。如下:

在這裏插入圖片描述


問題原因分析及結論

網上查閱資料發現,Linux下的TCP連接有這樣一個特性:對一個已經關閉的tcp socket進行寫操作,會觸發系統向當前進程發送SIGPIPE信號,而該信號的默認操作是退出當前進程。基於這樣的一個特性就不難了理解Linux下的表現了,同時也說明sylixos下沒有該特性。

具體的分析可以結合TCP的”四次握手”關閉。TCP是全雙工的信道,可以看作兩條單工信道,TCP連接兩端的兩個端點各負責一條。當對端調用close時,雖然本意是關閉整個兩條信道, 但本端只是收到FIN包。 按照TCP協議的語義,表示對端只是關閉了其所負責的那一條單工信道, 仍然可以繼續接收數據。也就是說,因爲TCP協議的限制,一個端點無法獲知對端已經完全關閉
在這裏插入圖片描述
對一個已經收到FIN包的socket調用read方法,如果接收緩衝已空,則返回0, 這就是常說的表示連接關閉。但第一次對其調用write方法時, 如果發送緩衝沒問題,會返回正確寫入。 但發送的報文會導致對端發送RST報文,因爲對端的socket已經調用了close,完全關閉,既不發送,也不接收數據。所以,第二次調用write方法(假設在收到RST之後), 會生成SIGPIPE信號,導致進程退出。


問題處理方法

如果不想讓直行進程直接退出,則可以有如下幾種方法解決:

  1. 設置socket屬性爲SO_NOSIGPIPE(異常時不發送SIGPIPE信號):
   setsocketopt(sock_fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int));
  1. 設置對SIGPIPE信號的處理方式爲SIG_IGN(忽略):
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &sa, 0 );
    或:
	signal(SIGPIPE, SIG_IGN);
	或:
	sigignore(SIGPIPE);
  1. 設置send主線程屬性:
	sigset_t signal_mask;  
	sigemptyset(&signal_mask); 
	sigaddset(&signal_mask, SIGPIPE);  
	pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);  

改進後測試

在循環前設置對SIGPIPE信號的處理方式爲忽略,修改代碼如下:

static  void   *tcpClientPthread (void * pvArg)
{
    ARG_ST  *parg = (ARG_ST  *)pvArg;
    signal(SIGPIPE, SIG_IGN);
    while (1) {
        tcpClient(parg);
        sleep(10);
    }

    return  (NULL);
}

測試修改後的代碼,現象如下,可見已經不會載自動退出當前進程了,和預期效果一樣。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章