網絡編程-TCP筆記

    很久沒寫博客了,最近也看了不少書,看完了好像印象不深,還是回頭寫寫記錄下吧。。

 

1.TCP機制
    TCP提供了可靠性 ,當TCP向另外一端發送數據時,它要求對端返回一個確認。如果沒有收到確認,TCP就自動重傳數據並等待更長的時間。在數次重傳失敗後,TCP才放棄,如此在嘗試發送數據上所花的總時間一般爲4-8分鐘(依賴具體實現)。
    TCP含有用於動態估算客戶和服務器之間的往返時間(round-trip time,RTT)的算法 ,以便它知道等待一個確認需要多少時間。
    TCP通過給其中每個字節關聯一個序列號對所發送的數據進行排序。 接受端TCP將先根據它們的序列號重新排序,再把結果數據傳遞給應用。如果收到重複的數據(根據序列號),將丟棄該數據。
    TCP提供流量控制。 TCO總是告知對端在任何時刻它一次能夠從對端接受多少字節的數據,這稱爲通知窗口(advertised window)。在任何時刻,該窗口指出接受緩衝區中當前可用的空間量,從而確保發送端發送的數據不會使接受緩衝區溢出。該窗口時刻動態變化,當接收來自發送端的數據時,窗口大小就減小,但是當接受端應用從緩衝區中讀取數據是,窗口大小就增大。通知窗口大小減小到0是有可能的,當TCP對應某個套接字的接受緩衝區已滿,導致它必須等待應用從該緩衝區讀取時間時,方能從對端再接受數據。

2.TCP連接的建立和終止
    TCP連接的建立的三路握手
 

 
    (1)通常通過調用socket/bind和listen這三個函數來完成,我們稱之爲被動打開(passive open)。
    (2)客戶通過調用connect發動主動打開(active open)。這導致客戶TCP發送一個SYN(同步)分節,它告訴服務器客戶將在(待建立的)連接中發送的數據的初始化序列號。通常SYN分節不攜帶數據,其所在IP數據報只含有一個IP首部/一個TCP首部及可能有的TCP選項。
    (3)服務器必須確認(ACK)客戶的SYN,同時自己也得發送一個SYN分節,它含有服務器將在同一連接中發送的數據和初始化序列號。服務器在單個分節中發送SYN和對客戶SYN的ACK(確認)。
    (4)客戶必須確認服務器的SYN。
這種交換至少需要3個分組,因此稱之爲三路握手。

    TCP連接的終止



 
 
 
    TCP連接的終止每個方向都需要一個FIN和ACK,通常需要4個分節,中間兩個分節也有可能合併成一個分節。而原理和建立發的包的原理差不多,看圖就能明白。

3.TCP狀態轉換圖
    這些狀態都可以使用netstat顯示。
 



 


 
 
 

    從上圖可以看出,值得注意的是,如果該連接的整個目的僅僅是發送一個單分節的請求和接收一個單分節的應答的請求和接受一個單分節的應答,那麼使用TCP有8個分節的開銷,如果改用UDP,那麼只需交換兩組:一個承接請求,一個承接應答,當然這也喪失了TCP的可靠性等特性。
    TIME_WAIT狀態
    TCP中有關網絡編程中TIME_WAIT狀態不容易理解。該端點停留在這個狀態的持續時間是最常分節生命期(maximum segment lifetime,MSL)的兩倍。TIME_WAIT狀態有兩個存在的理由:(1)可靠地勢險TCP全雙工連接的終止。該理由容易理解,主要是爲了發送最終的ACK(2)允許老的重複分節在網絡中消逝。該理由是說TCP必須防止來自某個連接的老的重複分組在該連接已終止後再先,從而被誤解成屬於同一連接的某個新的化身。

4.TCP三路握手

TCP中調用connect函數將激發三路握手,其中建立連接出現的錯誤可能有以下幾種:

   (1)若TCP客戶沒有收到SYN分節的響應,則返回ETIMEOUT錯誤。
   (2)若對客戶的SYN的響應是RST(復位),則表明該服務器主機在我們指定的端口沒有進程在等待與之連接(例如服務器進程也許沒在運行)。這是一種硬錯誤,客戶一接收到RST就馬上返回ECONNREFUSD錯誤。RST是TCP在發生錯誤時發送的一種TCP分節。產生RST的條件之:目的地爲某個端口的SYN到達,然而該端口上沒有正在監聽的服務器;TCP想取消一個已有連接;TCP接受到一個根本不存在的連接上的分節。
   (3)若客戶發生的SYN在中間的某個路由器上引發了一個“destination unreachable”ICMP錯哦無,則認爲是一個軟錯誤。客戶端保存該消息,並按照第一種情況中所述的時間間隔繼續發送SYN。若在某個規定的時間(BSD規定75s)後仍未收到響應,則把保存的消息作爲EHOSTUNREACH 或ENETUNRACH錯誤返回給進程。

5.服務器異常情況
    當服務器端被kill掉,將導致想客戶端發送一個FIN,然而如果客戶端在正在阻塞在可讀或者可寫狀態時,客戶端不作反應,知道下次讀或寫數據時,才響應該錯誤。這種情況可用其他方法解決,例如select函數或者設置SO_KEEPALIVE時間。

 

----以下是摘錄網上的TCP錯誤原因---

第1個異常是java.net.BindException:Address already in use: JVM_Bind。該異常發生在服務器端進行new ServerSocket(port)(port是一個0,65536的整型值)操作時。異常的原因是以爲與port一樣的一個端口已經被啓動,並進行監聽。此時用netstat –an命令,可以看到一個Listending狀態的端口。只需要找一個沒有被佔用的端口就能解決這個問題。 

第2個異常是java.net.ConnectException: Connection refused: connect。該異常發生在客戶端進行new Socket(ip, port)操作時,該異常發生的原因是或者具有ip地址的機器不能找到(也就是說從當前機器不存在到指定ip路由),或者是該ip存在,但找不到指定的端口進行監聽。出現該問題,首先檢查客戶端的ip和port是否寫錯了,如果正確則從客戶端ping一下服務器看是否能ping通,如果能ping通(服務服務器端把ping禁掉則需要另外的辦法),則看在服務器端的監聽指定端口的程序是否啓動,這個肯定能解決這個問題。 

第3個異常是java.net.SocketException: Socket is closed,該異常在客戶端和服務器均可能發生。異常的原因是己方主動關閉了連接後(調用了Socket的close方法)再對網絡連接進行讀寫操作。 

第4個異常是java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error)。該異常在客戶端和服務器端均有可能發生,引起該異常的原因有兩個,第一個就是如果一端的Socket被關閉(或主動關閉或者因爲異常退出而引起的關閉),另一端仍發送數據,發送的第一個數據包引發該異常(Connect reset by peer)。另一個是一端退出,但退出時並未關閉該連接,另一端如果在從連接中讀數據則拋出該異常(Connection reset)。簡單的說就是在連接斷開後的讀和寫操作引起的。 

第5個異常是java.net.SocketException: Broken pipe。該異常在客戶端和服務器均有可能發生。在第4個異常的第一種情況中(也就是拋出SocketExcepton:Connect reset by peer:Socket write error後),如果再繼續寫數據則拋出該異常。前兩個異常的解決方法是首先確保程序退出前關閉所有的網絡連接,其次是要檢測對方的關閉連接操作,發現對方關閉連接後自己也要關閉該連接。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章