使用libevent編寫websocket服務端時遇到了一個問題:
瀏覽器與服務端建立連接后,若刷新或關閉瀏覽器窗口(未監聽相應事件並處理),服務端無法得知連接斷開,按理說,這種情況屬於client異常終止,跟拔網線的情況類似。這種情況下,服務端不知情,仍保留此連接,仍按照既定邏輯向client寫數據,寫了兩次后,服務端程序終止(多次測試,均是第2次后終止),不是崩潰,是異常終止,非常不解。
問了一位很有經驗的同事,得知是SIGPIPE信號導致程序終止。
查了相關資料,大致明白:連接建立,若某一端關閉連接,而另一端仍然向它寫數據,第一次寫數據后會收到RST響應,此后再寫數據,內核將向進程發出SIGPIPE信號,通知進程此連接已經斷開。而SIGPIPE信號的默認處理是終止程序,導致上述問題的發生。
為避免這種情況,可以選擇忽略SIGPIPE信號,不執行任何動作。
#include <signal.h>
//SIGPIPE ignore
struct sigaction act;
act.sa_handler = SIG_IGN;
if (sigaction(SIGPIPE, &act, NULL) == 0) {
LOG("SIGPIPE ignore");
}