天天看點

Socket程式設計實踐(6) --TCP服務端注意事項

1)通過忽略SIGCHLD信号,避免僵屍程序

    在server端代碼中添加

    signal(SIGCHLD, SIG_IGN);

2)通過wait/waitpid方法,解決僵屍程序

3) 如果多個用戶端同時關閉, 問題描述如下面兩幅圖所示:

Socket程式設計實踐(6) --TCP服務端注意事項
Socket程式設計實踐(6) --TCP服務端注意事項

在客戶運作過程中按下Ctrl+C,則可以看到在server端啟動50個子程序,并且所有的用戶端全部一起斷開的情況下,産生的僵屍程序數是驚人的(此時也證明了SIGCHLD信号是不可靠的)!

Socket程式設計實踐(6) --TCP服務端注意事項

解決方法-将server端信号捕捉函數改造如下:

waitpid傳回值解釋:

  on  success,  returns the process ID of the child whose state has changed(傳回已經結束運作

的子程序的PID); if WNOHANG was specified and one or more child(ren) specified by pid exist, 

but have not yet changed state, then 0 is returned(如果此時尚有好多被pid參數辨別的子程序存在, 并

且沒有結束的迹象, 傳回0).  On error, -1 is returned.

Socket程式設計實踐(6) --TCP服務端注意事項

1.如下圖(用戶端與伺服器都在本機:雙方(server的子程序,與client)連結已經建立(ESTABLISHED),等待通信)

Socket程式設計實踐(6) --TCP服務端注意事項

2.最先close的一端,會進入TIME_WAIT狀态; 而被動關閉的一端可以進入CLOSE_WAIT狀态 (下圖,server端首先關閉)

Socket程式設計實踐(6) --TCP服務端注意事項

3.TIME_WAIT 時間是2MSL(封包的最長存活周期的2倍) 

  原因:(ACK y+1)如果發送失敗可以重發, 是以如果server端不設定位址重複利用的話, 伺服器在短時間内就無法重新開機;

    伺服器端處于closed狀态,不等于用戶端也處于closed狀态。

(下圖, client先close, client出現TIME_WAIT狀态)

Socket程式設計實踐(6) --TCP服務端注意事項

4.TCP/IP協定的第1種狀态:圖上隻包含10種狀态,還有一種CLOSING狀态

産生CLOSING狀态的原因:

Server端與Client端同時關閉(同時調用close,此時兩端同時給對端發送FIN包),将産生closing狀态,最後雙方都進入TIME_WAIT狀态(如下圖)。

Socket程式設計實踐(6) --TCP服務端注意事項

往一個已經接收FIN的套接中寫是允許的,接收到FIN僅僅代表對方不再發送資料;但是在收到RST段之後,如果還繼續寫,調用write就會産生SIGPIPE信号,對于這個信号的處理我們通常忽略即可。

    signal(SIGPIPE, SIG_IGN); 

shutdown的how參數

SHUT_RD

關閉讀端

SHUT_WR

關閉寫端

SHUT_RDWR

讀寫均關閉

1.close終止了資料傳送的兩個方向;

  而shutdown可以有選擇的終止某個方向的資料傳送或者終止資料傳送的兩個方向。

2.shutdown how=SHUT_WR(關閉寫端)可以保證對等方接收到一個EOF字元(FIN段),而不管是否有其他程序已經打開了套接字(shutdown并沒采用引用計數)。

  而close需要等待套接字引用計數減為0時才發送FIN段。也就是說直到所有的程序都關閉了該套接字。

示例分析:

   用戶端向伺服器按照順序發送:FIN E D C B A, 如果FIN是當client尚未接收到ABCDE之前就調用close發送的, 那麼client端将永遠接收不到ABCDE了, 而通過shutdown函數, 則可以有選擇的隻關閉client的發送端而不關閉接收端, 則client端還可以接收到ABCDE的資訊;

/**測試: 實作與上面類似的代碼(使用close/shutdown)兩種方式實作 **/

完整源代碼請參照:

<a href="http://download.csdn.net/detail/hanqing280441589/8486517">http://download.csdn.net/detail/hanqing280441589/8486517</a>

注意: 最好讀者需要有select的基礎, 沒有select基礎的讀者可以參考我的部落格&lt;Socket程式設計實踐(8)&gt;相關部分

繼續閱讀