tcp鏈接時,BROKEN PIPE錯誤的緣由以及解決方法

問題:網絡

寫了一個server和一個client,UNIX套接字的,server不斷接收消息並打印出來,client是一個交互程序,輸入一個消息回車發送,接着又能夠輸入消息。
出問題了:
當server監聽着,client第一次發送消息成功,server接收並打印出來了。
client第二次發送消息沒成功而且結束程序了,server沒接收到消息,保持繼續監聽。
我用GDB調試時,發現client第二次發送消息時,client收到SIGPIPE(Broken Pipe)信號。server明明還監聽着,並且再次啓動client仍是第一次成功,第二次失敗退出。socket

 一樣的,當client由於斷開(關閉了網絡描述符sfd,或者ctrl+c/ctrl+\異常斷開),server端也產生SIGPIPE信號。tcp

分析:spa

TCP協議是端到端的傳輸控制協議,之因此是「端到端」的協議,是由於」路由「是由IP協議負責的,TCP協議負責爲兩個通訊端點提供可靠性保證,這個可靠性不是指一個端點發送的數據,另外一個端點確定能收到(這顯然是不可能的),而是指,數據的可靠投遞或者故障的可靠通知。調試

所謂的「端到端」,指的是在通訊兩端之間創建了一個全雙工的通訊管道,既然是管道,就不得不瞭解管道。server

 

管道的特色:blog

  • 管道是半雙工的,數據只能向一個方向流動;須要雙方通訊時,須要創建起兩個管道;
  • 只能用於父子進程或者兄弟進程之間(具備親緣關係的進程);
  • 單獨構成一種獨立的文件系統:管道對於管道兩端的進程而言,就是一個文件,但它不是普通的文件,它不屬於某種文件系統,而是自立門戶,單獨構成一種文件系統,而且只存在與內存中。
  • 數據的讀出和寫入:一個進程向管道中寫的內容被管道另外一端的進程讀出。寫入的內容每次都添加在管道緩衝區的末尾,而且每次都是從緩衝區的頭部讀出數據。

管道特性的表現:進程

  • 若是一個進程以只寫打開管道,可是沒有以只讀或讀寫打開這個管道的進程,則打開操做會阻塞, 直到有進程以讀或讀寫打開,open 纔會返回。(寫端打開,讀端關閉)
  • 若是一個進程以只讀打開管道,可是沒有以只寫或讀寫打開這個管道的進程,則打開操做會阻塞, 直到有進程以寫或讀寫打開,open 纔會返回。(寫端關閉,讀端打開)
  • 當寫端沒有寫入數據時,讀端會阻塞到 read 調用,直到寫端寫入數據或者寫端關閉。 當管道沒有空間時,再寫入數據就會被阻塞。直到有進程讀取數據,或者全部的讀端關閉。(讀寫順序)

注意:全雙工,指的是每一端均可讀可寫。前提是對端打開若是對端都關閉了,本端讀數據爲空,不會出錯;但本段寫數據確定出錯。ip

總結:內存

若是要進行順利的管道通訊:管道的兩端必需都打開。

  • 管道讀端關閉,寫端不能寫,不然會發出SIGPIPE信號,即會生成BROKEN PIPE錯誤。

也就是說tcp通訊時,client端經過 pipe發送信息到server端後,client端掛沒必要,這時server端返回信息,向pipe些內容,就會出錯。

 

解決方法:

  • 忽略SIGPIPE信號

    一、signal(SIGPIPE,SIG_INT);//(全局範圍內)

    二、setsocketop;//(tcp特性設置)

/// sock 就是設置不發送 `SIGPIPE` 信號的 socket 變量
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
  • 合理規避讀端關閉,寫端打開的問題。(避免client端關閉,server端發送數據這種狀況)
相關文章
相關標籤/搜索