1. 程式人生 > >tcp 狀態機中的reset標誌

tcp 狀態機中的reset標誌

   從前面的tcp flag可以看出,reset這個標示作為tcp協議棧的設計來說,也是十分重要的。

    傳送RST包關閉連線的時候,不必等緩衝區的包都發出去,直接就丟棄緩衝區的包傳送RST包。

    而接收端收到RST包,也不必傳送ACK包來確定。

    具體有下面的情況:

    第一:埠沒有開啟,伺服器埠沒有開啟而客戶端來連線。

    第二:請求超時!比如,客戶端連線服務端,connect返回-1並且error = EINPROGRESS。
    具體的例子:有89、27兩臺主機。主機89向主機27傳送了一個SYN,表示希望連線8888埠,主機27迴應了主機89一個SYN表示可以連線。但是主機27卻很不友好,莫名其妙的傳送了一個RST表示我不想連線你了。

    通過排查,在主機89上的程式在建立了socket之後,用setsockopt的選項設定了recv的超時時間為100ms。而我們看上面的抓包結果表示,從主機89發出SYN到接收SYN的時間多達110ms。(從15:01:27.799961到15:01:27.961886, 小數點之後的單位是微秒)。因此主機89上的程式認為接收超時,所以傳送了RST拒絕進一步傳送資料。

第四:關於TCP,我想我們在教科書裡都讀到過一句話,'TCP是一種可靠的連線'。 而這可靠有這樣一種含義,那就是作業系統接收到的來自TCP連線中的每一個位元組,我都會讓應用程式接收到。如果應用程式不接收怎麼辦?你猜對了,RST。意思就是說:客戶端開啟socket,然後connect伺服器,傳送5000個位元組,而此時的伺服器只是接收4096個位元組,那麼客戶端傳送剩下的4個位元組伺服器沒有收到,於是socket就被關閉了,此時就會發送rst。

第四:斷掉的情況,

    A,B兩端tcp建立連線後,如果中間的交換機斷網、斷電,或者B端突然斷電,那麼A是無感知的(不考慮心跳機制)。有些書上喜歡把這種連線叫半開連線,其實我更願意叫它為死連線。

   此時,如果A端send一些資料,會怎樣呢?只要A端的傳送核心緩衝區沒有滿(一般都沒滿),那麼send函式就是成功返回得,很顯然,在B端是接收不到資料的.這再次說明了,send函式和實際傳送數沒有半毛錢的關係,這一點,我們在之前的博文中多次說過。

   A傳送資料後,期望收到B的ACK包,但顯然收不到,於是,A端的協議棧會自動進行重傳,這是tcp最基本的機制之一,當重傳次數達到一定上限後,就會發RST包,重置連線,死連線就徹底死了。

 下面的情況都不會發送RST,需要構造linger這個架構體!

  1. 使用shutdown、close關閉套接字,傳送的是FIN,不是RST

      2. 套接字關閉前,使用sleep。對執行的程式Ctrl+C,會發送FIN,不是RST

      3. 套接字關閉前,執行return、exit(0)、exit(1),會發送FIN、不是RST。 

      以上幾種方法,都不能傳送RST包。 傳送RST包,需要自己偽造資料包進行傳送。

                  那麼從程式碼角度來看,暫時先參考這個文章,後續會繼續深入協議棧,看這個問題,先討論到這裡!

           http://www.cnblogs.com/scottieyuyang/p/5713905.html