關於檢測TCP連線斷開

director_匠發表於2017-11-10

    因為專案需求,需要用到linux下的C程式設計來開發,之前都是在STM下進行的。所以對linux的一些API和開發的一些小技巧不是特別的熟悉。因為專案的網路通訊是用在TCP協議上的。在連線的時候 如果伺服器斷開了,客戶端也相應斷開,但是如果伺服器再繼續連線,這時候客戶端應該要進行重新連線,所以要有一個機制進行檢測,之前用recv的返回值如果是-1則進行重連,因為重連之前要關閉socket號,會發現這樣子很容易一直在反覆連線。不合理,所以參考了http://blog.sina.com.cn/s/blog_6b633e8f0100kt39.html這個部落格進行了修改。

當伺服器close一個連線時,若client端接著發資料。根據TCP協議的 規定,會收到一個RST響應,client再往這個伺服器傳送資料時,系統會發出一個SIGPIPE訊號給程式,告訴程式這個連線已經斷開了,不要再寫 了。
根據訊號的預設處理規則SIGPIPE訊號的預設執行動作是terminate(終止、退出),所以client會退出。若不想客戶端退出可以把 SIGPIPE設為SIG_IGN

如:signal(SIGPIPE, SIG_IGN);
這時SIGPIPE交給了系統處理。

伺服器採用了fork的話,要收集垃圾程式,防止殭屍程式的產生,可以這樣處理:
signal(SIGCHLD,SIG_IGN);
交給系統init去回收。
這裡子程式就不會產生殭屍程式了。


在linux下寫socket的程式的時候,如果嘗試send到一個disconnected socket上,就會讓底層丟擲一個SIGPIPE訊號。
這個訊號的預設處理方法是退出程式,大多數時候這都不是我們期望的。因此我們需要過載這個訊號的處理方法。呼叫以下程式碼,即可安全的遮蔽SIGPIPE:
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &sa, 0 );

signal設定的訊號控制程式碼只能起一次作用,訊號被捕獲一次後,訊號控制程式碼就會被還原成預設值了。
sigaction設定的訊號控制程式碼,可以一直有效,值到你再次改變它的設定。

struct sigaction action;
action.sa_handler = handle_pipe;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGPIPE, &action, NULL);
void handle_pipe(int sig)
{

        //先關閉之前的socket號 再進行重新連線
}


相關文章