TCP基礎

TCP報文段: 概念:分爲頭部和數據兩部分。編程

TCP報文段頭部中的字段:
	源端口/目的端口	這兩個字段與IP頭部中的源IP地址和目的IP地址一塊兒, 惟一地標識了每一個鏈接。一個ip地址和一個端口的組合被稱爲一個socket或一個endpoint。
	序列號(seq)		本報文段所發送的數據的第一個字節的序列號,seq的值等於前面已發送過的數據的最後一個字節的序列號+1。(TCP傳輸時將每一個字節的數據都進行了編號,這個編號就是序列號)
	確認號(ack)		指望收到對方下一個報文段的第一個數據字節的序列號,若ack爲x,則到序號x-1爲止(包括x-1)的全部數據都已正確收到。
	確認(ACK)		僅當ACK=1時,ack字段纔有效,當ACK=0時,ack無效。
	同步(SYN)		SYN=1且ACK=0 代表這是一個鏈接請求報文段,若對方贊成創建鏈接,則對方應在響應報文中包含SYN=1和ACK=1。
	終止(FIN)		FIN=1代表此報文的發送方已經結束向對方發送數據,並要求釋放鏈接。
	重置(RST) 		重置鏈接。
	窗口大小			接收端接收緩衝區剩餘的大小。這是一個16位的字段,單位是字節數。窗口大小字段最大能表示65535個字節(64K),
					可是TCP的接收窗口大小最大並非64K。TCP實際的接收窗口大小爲16位窗口大小字段的值左移M(M表示:窗口擴大因子)位,每移一位,窗口擴大兩倍。

	校驗和 			該字段覆蓋了TCP頭部和數據,由發送方進行計算,而後由接收方來驗證。
					其目的是爲了發現TCP頭部和數據在發送端到接收端之間發生的任何改動,若是接收方檢測到校驗和有差錯,則TCP報文會被直接丟棄。


	說明:
		在鏈接創建後全部傳送的報文都必須把ACK置1。
		SYN報文段、FIN報文段不能攜帶數據,但會消耗掉一個序列號。
		ACK報文段能夠攜帶數據,但若是不攜帶數據則不消耗序列號。

TCP數據

TCP三次握手緩存

概念:創建一個TCP鏈接時,客戶端和服務器須要交互3次,即發送3次TCP報文段,故稱爲3次握手。

目的:與服務器創建TCP鏈接,並同步鏈接雙方的序列號、確認號、TCP窗口大小等信息。

說明:
	三次握手改成兩次握手會產生死鎖:
		兩次握手:A發送鏈接請求報文,B接收A的請求報文併發出確認報文後,則認爲鏈接創建。
		舉例:A發送鏈接請求報文,B收到A的請求報文併發出確認報文,若是B的肯定報文在傳輸過程當中丟失了,此時,B認爲鏈接已創建並開始發送數據,而A一直在等待着B的肯定報文,且不會接受B發送的數據,而B在發送數據後將一直處於等待A肯定的狀態中,從而形成A和B相互等待,造成死鎖。

第一次握手:
	客戶端向服務器發出鏈接請求報文段(報文段頭部:(初始)序列號seq=x、同步SYN=1),此時客戶端進入SYN_SENT(同步已發送)狀態。
	說明:同步SYN=1會消耗一個序列號位,即把x這個序列號位給佔了,故下次發送的序列號應該從x+1開始,第一次揮手時的FIN也同理。

第二次握手:
	服務器收到鏈接請求報文段後,若贊成創建鏈接,則向客戶端發送響應報文段(報文段頭部:同步SYN=一、確認ACK=一、確認號ack=x+一、序列號seq=y,此時服務器進入SYN_RECV(同步已收到)狀態。此時的TCP鏈接稱爲半鏈接(half-open connect)。

第三次握手:
	客戶端收到服務器的響應報文段後,再次向服務器發出用於確認的報文段(報文段頭部:同步SYN=0、確認ACK=一、確認號ack=y+一、序號seq=x+1),此時TCP鏈接已創建,客戶端和服務器都進入ESTABLISHED(已創建鏈接)狀態。

TCP四次揮手服務器

概念:釋放一個TCP鏈接時,客戶端和服務器須要交互4次,即發送4次TCP報文段,故稱爲4次揮手。

說明:
	1)斷開TCP鏈接 即 客戶端關閉發送數據的通道 而且 服務器關閉發送數據的通道。
	2)爲何鏈接的時候是三次握手,關閉的時候倒是四次握手:
		1>創建鏈接時:當Server端收到Client端的SYN鏈接請求報文後,Server端能夠直接發送SYN+ACK報文,其中ACK報文是用來應答的,SYN報文是用來同步的。
		2>關閉鏈接時:當Server端收到Client端的FIN報文後,Server端極可能不會當即關閉SOCKET,而是先回復一個ACK報文,告訴Client端,"你發的FIN報文我收到了,可是我(可能)還有數據要發送",當Server端全部的報文都發送完了,Server端纔會發送FIN報文,即Server端通知Client端的過程當中須要揮兩次手,故在關閉鏈接的時候總共須要四次揮手。

第一次揮手:
	客戶端向服務器發出鏈接釋放報文段(報文段頭部:終止FIN=一、序號seq=u),並中止發送數據,主動關閉TCP鏈接,此時客戶端進入FIN_WAIT1(終止等待1)狀態。

第二次揮手:
	服務器收到客戶端的鏈接釋放報文段後,向客戶端發送確認報文段(報文段頭部:確認ACK=一、確認號ack=u+一、序號seq=v),此時服務器進入CLOSE_WAIT(關閉等待)狀態,並通知應用進程。
	客戶端收到服務器的確認報文段後,進入FIN_WAIT2(終止等待2)狀態。
	此時,客戶端已經沒有數據要發送了,可是服務器可能還有數據要發送,且客戶端依然能夠接受服務器發送的數據,此時的TCP鏈接處於半關閉狀態。

第三次揮手:
	應用進程通知服務器釋放鏈接後,服務器發出鏈接釋放報文段(報文段頭部:確認ACK=1,終止FIN=一、序號seq=w(在半關閉狀態時服務器可能又發送了一些數據)、確認號ack=u+1),此時服務器進入LAST_ACK(最後肯定)狀態。

第四次揮手:
	客戶端收到服務器的鏈接釋放報文段後,向服務器發送肯定報文段(報文段頭部:確認ACK=一、序號seq=u+一、確認號ack=w+1),此時客戶端進入到TIME-WAIT(時間等待)狀態,等到等待時間事後,兩者才都進入到CLOSED(關閉)狀態。

SYN攻擊: 概念:SYN攻擊是一個典型的DDOS(Distributed Denial of Service:分佈式拒絕服務)攻擊。cookie

原理:
	客戶端在短期內僞造大量不存在的IP地址,而後向服務器不斷地發送SYN包(即不斷地發起第一次握手,創建大量的半鏈接狀態的請求),
	服務器收到鏈接請求後發送響應報文,並等待客戶的確認,因爲源地址是不存在的,故服務器須要不斷的重發直到超時,
	這些僞造的SYN包將長時間佔用未鏈接隊列(syns queue),正常的SYN請求被丟棄,目標系統運行緩慢,嚴重者引發網絡堵塞甚至系統癱瘓。

檢測:
	查看狀態爲SYN_RECV的TCP鏈接:	netstat -npt | grep SYN_RECV   # 若Foreign Address的ip地址是隨機的,則服務器此時極可能正在被SYN攻擊。
	統計TCP鏈接的狀態:			netstat -npt | awk '{print $6}' | grep -v "Foreign" | sort | uniq -c

說明:通常較新的TCP/IP協議棧都對這一過程進行修正來防範SYN攻擊,修改tcp協議實現。主要方法有SynAttackProtect保護機制、SYN cookies技術、增長最大半鏈接和縮短超時時間等.可是不能徹底防範SYN攻擊。

socket編程: Socket.connect() 會觸發TCP的三次握手。 Socket.close() 會觸發TCP的四次揮手。表示不發送數據也不接受數據了。網絡

超時重傳: 概念:TCP傳輸數據時,發送方發送數據後會等待接收方響應的ACK報文,並根據ACK報文來判斷數據是否傳輸成功。若是發送方發送完數據後,長時間沒有等到接收方的ACK報文,那麼發送方會從新發送這些數據。併發

發送方沒有收到ACK報文的緣由:
	數據在傳輸過程當中因爲網絡緣由等直接全體丟包,接收方根本沒有接收到。
	接收方接收到了響應的數據,可是響應的ACK報文卻因爲網絡緣由丟包了。以後接收方若再次收到發送方從新發送的數據(根據序列號可判斷是不是重複數據),則會將這些重複的數據丟棄,可是仍然會響應ACK報文。

超時時間的計算:
	默認500ms,重發一次後,若仍沒有響應,那麼等待2*500ms的時間後,再次重傳。重傳的次數達到某個值後,TCP就認爲網絡已經斷了或對方出現異常了,而後強制關閉鏈接。
	超時時間過長會下降TCP傳輸的總體效率。超時時間太短會致使頻繁的發送重複的包。

窗口機制: 概念:每一個TCP鏈接的兩端都維護了一個發送窗口和一個接收窗口。socket

發送窗口:
	發送方的發送緩存內的數據均可以被分爲4類,其中類型2和類型3屬於發送窗口:
		1>已發送,已收到ACK 
		2>已發送,未收到ACK 
		3>未發送,但容許發送 
		4>未發送,但不容許發送
接收窗口:
	接收方的緩存數據分爲3類,其中類型2屬於接收窗口:
		1>已接收 
		2>未接收但準備接收 
		3>未接收並且不許備接收

滑動機制:
	發送窗口只有收到發送窗口內字節的ACK確認後,纔會移動發送窗口的左邊界。
	接收窗口只有在前面全部的報文段都確認的狀況下才會移動左邊界。
	若接收窗口前面還有字節未接收,此時若是收到後面的字節,則接收窗口不會移動,TCP也不會對後面的字節發送確認,發送方超時後會重傳這些數據。

流量控制: 概念:TCP根據接收端對數據的處理能力(窗口大小字段的值)來決定發送端的發送速度。 過程: 接收端在確認應答時發送ACK報文,ACK報文中包含了本身接收窗口的大小,發送方根據ACK報文裏窗口大小的值的來設定本身發送數據的速度。 若ACK報文中窗口大小的值爲0,那麼發送方將中止發送數據,並按期向接收端發送窗口探測數據段,以便及時地獲取接收端最新窗口大小的值。tcp

說明:若是發送端發送的數據太快,則接收端的接收緩衝區很快就會被填滿,接受端的接收緩存區被填滿後,發送端再發送的數據就會被接收端丟棄,進而觸發發送端的超時重傳。

擁塞控制: 概念:路由器因沒法處理高速率到達的流量而被迫丟棄數據的現象稱爲擁塞。 擁塞的緣由:當路由器在單位時間內接收到的數據量大於其可發送的數據量時,路由器就須要把多餘的數據存儲起來。若接收到的數據量持續大於可發送的數據量,那麼會耗盡路由器的存儲資源,致使路由器丟棄部分數據。分佈式

原理:發送方維持一個擁塞窗口變量cwnd,擁塞窗口的大小取決於網絡的擁塞程度,發送方的發送窗口大小取 擁塞窗口的大小 和 接收端的接收窗口大小 的較小值,TCP經過動態地調整發送窗口的大小來實現擁塞控制。

慢啓動機制:
	擁塞窗口的初始值爲1,發送方每次收到ACK報文後,將擁塞窗口的值加1。
	慢啓動中的"慢",表示剛開始發送的數據少,發送的速度慢,可是擁塞窗口值的增加是指數級別的增加,故增加的很是快。當擁塞窗口的值達到閾值時,擁塞窗口值的增加就改成線性增加。
	在慢啓動開始的時候,慢啓動的閾值等於窗口的最大值,TCP一旦發現網絡擁塞,慢啓動的閾值將會變爲當前閥值的一半,同時擁塞窗口重置爲1。

TCP的可靠性: 鏈接管理:三次揮手四次握手 傳輸數據: 序列號和確認號機制 校驗和 超時重傳機制 流量控制 擁塞控制code

常見問題:

服務器返回「RST」的問題: 分析:服務器關閉connection後,若客戶端還在connection上讀寫,服務器內核接收到數據後發現Socket已經close了,此時服務器會返回「RST」標誌給客戶端。 說明: 服務器返回了「RST」時,若此時客戶端正在從Socket套接字的輸出流中讀數據則會提示Connection reset」 服務器返回了「RST」時,若此時客戶端正在往Socket套接字的輸入流中寫數據則會提示「Connection reset by peer」

解決:重試。
相關文章
相關標籤/搜索