防止 Nginx處理完后調用close關閉連接后 ,若緩沖區任然接收到客戶端發來的內容 ,則服務器會向客戶端發送RST包關閉連接,導致客戶端由於收到了RST而忽略了 http response
(當一個進程向某個已收到RST的套接字執行寫操作時,內核向該進程發送一個SIGPIPE信號);
上面Nginx調用了close 就會同時關閉 服務器端的 讀 和 寫 此時如果客戶段仍然有請求即向Nginx服務器寫數據 即第一次服務器會回復一個 RST包 第二次 當一個進程向某個已收到RST的套接字執行寫操作時,內核向該進程發送一個SIGPIPE信號 客戶段自己會掛掉啊 那就會忽略了 網絡中未到達或者已經到達的 http response
做一個很簡單的通信模塊:服務器端監聽服務請求並接收數據;客戶端連接服務器段並發送數據。考慮到 一種情況:客戶端向服務器端連續兩次發送數據,而服務器端在accept之后就關閉了連接。
通過在服務器端accept成功之后調用close(fd)模仿這種情形。UNP的5.13節說客戶端在第二次發送數據時會接收到第一次發送數據時服務器端返回的RST從而導致內核發出SIGPIPE信號。於是我在客戶端程序中使用signal(SIGPIPE, sig_pipe)捕捉SIGPIPE信號,程序調試時證明UNP說得沒錯,但在運行狀態時有時候捕捉不到SIGPIPE信號。
仔細看書,UNP第113面的5.12節中有一小段文字講RST被客戶端收到的時間取決於時序問題,於是猜想第二此調用send函數發送數據時有可能服務器端的RST還未返回。為了驗證這個猜想,在第二次發送數據前sleep一下程序,使得RST能在send前返回。測試程序,乖乖,這次都能捕捉到SIPPIPE信號了。
問題是:假如我想100%的捕捉SIGPIPE信號,那么每次的sleep就會影響到程序的效率。
服務器端SIGPIPE信號問題 可以類推到上面Nginx為什么需要延遲關閉了
客戶端進程突然斷開(進程被kill掉)時,被kill的進程在終止處理的工作中關閉所有該進程打開的描述符,這導致了一個FIN被發送給了服務器,服務器接收以后回復一個ACK;至此,該過程完成了四次揮手的前半個部分;然而此時在服務器上與客戶端保持連接的該進程正在將文件流發往客戶端,服務器上的該進程還並未調用close或shutdown函數,因此四次揮手的后一部分尚未完成;
根據上述,由於四次揮手沒有完成后一部分,服務器仍然能向客戶端發送數據,第一次數據到客戶端后,客戶端會響應一個RST,服務器接收后仍在向緩沖區發送數據,此時,內核向該進程發送一個SIGPIPE信號;
(當一個進程向某個已收到RST的套接字執行寫操作時,內核向該進程發送一個SIGPIPE信號);
注意:SIGPIPE信號的默認行為是終止進程,因此服務器進程退出;
---------------------