TCP三次握手四次揮手都做了什麼?

三次握手做了什麼

三次握手和四次揮手都位於傳輸層

1 建立連接

  1. 調用socket,創建fd

  2. 調用connect,向服務器發起連接請求

  3. connect會發出SYN段,並阻塞等待服務器應答(第一次)

  4. 服務器收到客戶端的SYN,會應答一個確認收到即SYN+ACK段來表示 “同意建立連接”(第二次)

  5. 客戶端收到服務器的SYN+ACK後,會從connect()返回,同時向服務器應答一個ACK,確認收到(第三次)

TCP客戶端和服務器建立連接的過程,稱爲三次握手

2 數據傳輸過程

1.,TCP協議提供全雙工的通信服務;全雙工(同一時刻,同一連接中通信雙方可同時寫數據)

  1. 建立連接後,服務器從accept()返回返回後立刻調用read(),讀socket就像管道一樣,如果數據未到達就阻塞等待到達就從read()返回

  2. 服務器阻塞等待時客戶端調用write()發送請求給服務器,服務器收到後從read()返回,對客戶端的請求進行處理。服務器在處理客戶端請求期間,客戶端也調用read阻塞等待服務器的應答.

服務器調用write()將處理的結果發送給客戶端後,繼續調用read()阻塞式等待客戶端的下一條請求。

  1. 客戶端從read()返回,繼續發送下一條數據,這樣循環下去,否則準備斷開連接(四次揮手)。

四次揮手又做了什麼

3 斷開連接

  1. 如果客戶端沒有更多的請求,就調用close()關閉連接,此時客戶端會向服務器發送FIN(第一次)

  2. 此是服務器收到FIN後,會迴應一個ACK,同時read()返回0 (第二次)

  3. read()返回之後,服務器就知道客戶端關閉了連接,也調用close()關閉連接,這個時候服務器會向客戶端發送一個FIN(第三次)

  4. 客戶端收到FIN,最後再返回一個ACK給服務器(第四次)

斷開連接的過程稱爲四次揮手

要清楚:read()是讀請求的,write()是用來讀響應的。

connect函數和TCP交互是通過發出SYN段
read()返回,說明收到了FIN 段

connect成功之後,
服務器
accept返回,並分配新的文件描述符和客戶端通信。
read(fd_,buf,size)阻塞等待客戶端數據請求
write(fd,buf,size)發送數據應答。

應用層

應用層的作用: 據說程序員寫的網絡程序基本都在應用層來進行編寫,可見應用層重要性

再談協議: 協議是一種約定,通信雙方事先制定好的

HTTP協議

雖然我們說應用層的協議都是我們程序員自己定製的,實際上,大佬已經給我制定好了,我們拿來直接用就好了。
http協議-------超文本傳輸協議 。就是其中之一。

認識URL
平時我們所說的網址其實就是URL;
https://editor.csdn.net/md?articleId=104169840

協議名:https
articleId : 查詢字符串
104169840:片段標識符
csdn.net:服務器地址
/md?:帶層次的文件路徑

在這裏插入圖片描述

’ + ‘ 被轉譯成了%2B

urldecode : 反轉譯
urlencode : 轉譯

來看一個fiddler抓包情況
在這裏插入圖片描述

看右側的Raw

** 1 http請求(上面的):**

在這裏插入圖片描述

  1. 首行:方法 + url + 版本

  2. Header: 請求的屬性,冒號分隔的鍵值對;每組屬性之間使用\n來分隔 ,即換行分割
    遇到空行說明Header部分結束

3.Body空行後面的內容都是Body,Body允許爲空字符串,如果Body存在,則在Header中會有一個Content-length屬性來標識Body的長度;

2 http 響應(下邊的)
在這裏插入圖片描述

  1. 首行:版本號 + 狀態碼 + 狀態解釋

  2. Header:請求的屬性,冒號分隔的鍵值對,每組屬性之間\n 分隔,行分割,遇到空行表示Header結束

  3. Body :空行後邊的全是Body,Body存在,則在Header後有一個Content-Length屬性標識Body的長度,如果服務器返回一個html頁面,那麼頁面內容就在Body中;

HTTP的方法

方法 說明 支持的HTTP協議版本
GET 獲取資源 1.0、1.1
POST 傳輸實體主體 1.0、1.1
PUT 傳輸文件 1.0、1.1
HEAD 獲得報文首部 1.0、1.1
DELETE 刪除文件 1.0、1.1
OPTIONS 詢問支持的方法 1.1
TRACE 追蹤路徑 1.1
CONNECT 要求用隧道協議連接代理 1.1
LINK 建立和資源之間的聯繫 1.0
UNLINK 斷開連接關係 1.0

其中最常見的就是 GET 和POST

HTTP狀態碼

狀態碼 類別 原因
1XX 信息性 請求正在處理
2XX 成功 正常處理完畢
3XX 重定向 需進行附加操作來完成
4XX 客戶端錯誤碼 服務器無法處理
5XX 服務器錯誤碼 服務器處理請求失敗

最常見的狀態碼:
200(OK)
404(Not Found)客戶端請求有問題
403(Forbidden) 禁止訪問
302 (Redirect)重定向
504 (Bad GateWay) 網關超時

HTTP最常見的 Header

Content-Type 數據類型(text/html等)

Content-Length Body長度

Host:客戶端高速服務器,請求的資源在那個端口上;

User-Agent:聲明用戶的操作系統和瀏覽器的版本信息

Referer:聲明當前頁面從哪個頁面過來的

location:搭配3XX狀態碼使用,告訴客戶端接下來去哪裏訪問

Cookie:用於在客戶端存儲少量的信息,通常用於實現會話功能。它保存在客戶端瀏覽器,是一個字符串,字符串協議程序員可以自己約定

IP協議

1 地址管理
ipv4 32位
地址不夠怎麼辦;  
		1  動態分配            主機聯網才分配,斷網就回收
		 2 :NAT 機制		  局域網內共用一個IP
		 3	ipv6
	
2 路由選擇

  IP地址爲 點分十進制 192.169.1.106
  1 同一個網段內的主機網絡好一定相同,主機號一定不同。(出現特例一定不能正常上網)
  2 相鄰網段(連接在一個路由器上的)的主機,網絡號一定不相同。
主機地址全0  就成爲 了 網絡號,代表此局域網
主機地址全1  就成了廣播地址。(UDP能廣播,TCP不能廣播)

私網IP 和 貢丸IP
私網IP 局域網內部使用
1: 10.*前8位是網絡號	
2:172.16.* --- 172.31.*  前12位是網絡號
3:192.168.* 
其餘 均爲公網ip


路由選擇(類似於導航)
路由選擇的過程就是進行路由間相互問路的過程。

爲了防止一臺路由器掛掉導致整個體系癱瘓,我們常做多份備份路由,叫做冗餘。	




route指令查看路由表

數據包 來到路由器後 ,跟子網掩碼Genmask 相與,相與結果再在Destination中找目的IP,找到了一樣的就發送,沒有就找下一跳(default) ,

數據鏈路層:

以太網,  以太網 不是一種具體的網絡,而是一種技術標準。稱爲協議


以太網爲什麼存在MTU?
  因爲硬件的緣故,必須要求數據幀在1500字節範圍內	

MTU在數據鏈路層中 ,最大的數據幀爲1500字節,不同協議中,MTU最大值也不同	



加入要發送的數據幀大於MTU,就會將數據幀分解,前幾部分都是1500字節,後邊餘多少就是多少了。


**

DNS域名解析協議

**

**DNS是一套從域名映射到IP的系統**

IP地址 + 端口號 來進行唯一確定一臺主機上的一個進程
因爲IP地址不好記,人們就發明了主機名(string),
並用hosts文件來管理維護主機名和IP的地址關係。

假如DNS服務器掛掉了,全世界的人民都上不了網了嗎?
   大佬都想好方案:採用分佈式的DNS服務器,在全球建立多個DNS系統(類似於路由冗餘)	

DNS 地址;
8.8.8.8   谷歌維護的全球的根域名解析服務器  ---
114.114.114.114


在局域網中 ,路由器自己也維護了一個映射關係
內網IP和端口映射一個路由器IP和端口號   所以外網感知不到局域網內網(內部主機)
因爲端口號的數量是有限的,所以  NAT只能維護端口號範圍內的主機數量的網絡


在瀏覽器中輸入一個url都發生了什麼?我們可以從以下幾個角度進行分析:

1  從操作系統管理硬盤設備角度:

2  從網絡通信的角度看: 
	1  進行DNS域名解析
	2  HTTP角度
	3  從自定製協議的角度(URL中關鍵字的query string怎麼設計,body都包含了什麼內容等等,cookie)

3 從傳輸層的角度
  	1  TCP連接建立的角度
	2  長短連接的角度(一個TCP連接涵蓋好幾個HTTP的交互過程  稱爲長連接)  好處:開銷小效率高

4 從網絡層和數據鏈路層的角度
	1 從IP地址的相關規則
	2 路由選擇的角度
	3 數據鏈路層的相關規則

5 通信原理的角度(謹慎哦,不清楚別提)  

	瀏覽器 (外部也可連接一個CDN )   
    	搜索入口服務器
		(1 分詞服務器 
		 2 檢索服務器 
		 3 物料服務器(查詢最終數據)  
		 4 用戶服務器(用戶的一些信息) 
		 5 廣告服務器(類似於搜索入口服務器))	
	
		分佈式服務器使用大量的反向代理服務器 :就像各種運營商提供的服務器一樣

		負載均衡:

		1  提高效率
		2 提高可靠性
		3 可伸縮性(通過增加或減少服務器的數量來讓負載均衡)

在TCP/IP中 ,用源IP,源端口號 ,目的IP,目的端口號,協議號這個五元組,來表示一個通道,可以通過 netstat - n命令查看;

端口號 分爲知名端口號操作系統動態分配的端口號

知名端口號 0 - 1023
操作系統動態分配端口號 ;1024 - 65535

ssh服務器: 22端口
http服務器: 80端口
ftp服務器: 21端口
https服務器: 443端口
telnet服務器: 23端口

cat /etc/services 命令查看所有知名端口號

UDP協議

UDP協議端格式

|-16位源端口號 -|16位目的端口號 |
|-16位UDP長度-|-16位UDP檢驗和-|
| ——————數據(可有可無)-|

16位 UDP長度代表數據部分+UDP首部,表示整個數據報的最大長度
它與16位檢驗和若不相等,則丟棄。

UDP的特點:

  • 無連接
    知道對方的IP和 port就直接發送,不用建立連接,代碼中不會connect。

  • 不可靠
    1沒有確認機制,
    2沒有重傳機制。
    如發生網絡故障,UDP協議層不會給應用層返回故障信息。

  • 面向數據報
    不能靈活的控制讀取數據的次數和數量(長度)。
    面向數據報也意味着應用層發送給UDP多長的報文,UDP原樣發送,不會拆分,也不會合並。
    eg:如果發送端一次sendto()100字節數據,那麼接受端也只能一次recvfrom()100字節,而不能分多次接收。

  1. UDP不存在真正意義的發送緩衝區 ,發送數據時,調用sendto, 將要發送的數據交給內核,由內核將數據傳給網絡層協議,並進行後續操作。
  2. UDP具有接收緩衝區,,但這個接收緩衝區不能保證收到的數據順序和發送時的順序一致,而且若緩衝區滿了,後續數據會被丟棄。

另外,UDP的socket 既能讀,也能寫,即全雙工

因爲 UDP協議首部中說 UDP16位長,那麼最大數據長度+首部的長度爲2^16 ,即 64K,
那麼如果我們要發送的數據大於 64K ,我們就得在應用層進行手動分包,多次發送,同樣還得在接收端進行手動拼裝。

TCP協議

TCP全稱傳輸控制協議。

TCP6個標誌位

  1. URG:緊急指針是否有效
  2. ACK:確認好是否有效
  3. PSH:提示接收端應用程序立刻將緩衝區數據讀走。
  4. SYN:請求建立連接。我們把攜帶SYN標識的稱爲同步報文段
  5. RST:對方要求重新建立連接。復位報文段
  6. FIN:請求斷開連接。結束報文段。。

16位校驗和:由發送端填充,在接受端進行CRC(循環冗餘檢驗),檢驗不通過,則認爲接收數據有問題。

16位緊急指針:標識哪部分數據是緊急數據。

確認應答機制ACK

eg:
客戶端發送數據1-1000
服務器確認應答下一個1001,

TCP 將每個字節的數據都進行的編號,即序列號

每一個ACK都帶有對應的確認序列號,意思是告訴發送者,我們已經收到了哪些數據,下一次你從哪裏開始發。

超時從傳機制

主機A發送數據給主機B ,但可能因爲網絡問題等,主機B遲遲未收到該數據,
此時,主機A在特定的時間段內,未收到主機B的確認應答,就會進行重發。。

但!! 主機A未收到主機B的確認應答,也可能是主機B的確認應答ACK丟失了。

這時,主機B就會收到重複的數據,,所以TCP協議需要能夠識別哪些是重複的數據,需要將重複的數據丟棄,這時,我們就可以利用序列號了,利用序列號可以很容易的達到去重的目的。

那麼,超時重傳的世間如何設定?

	不同的網絡環境,超時重傳的時間會存在差異
	**TCP**爲了保證在任何網絡環境下都能最大效率的
	保證重傳,**會動態計算**該網絡情況下的**超時重傳時間**。

Linux下以500ms作爲超時重傳的單位。,
重發,仍得不到應答,時間將指數形式增加,(每次✖️2)

當累積重傳到一定次數時,,TCP會認爲主機連接存在問題(網絡,或對端主機連接問題),並強制關閉。

連接管理機制

在正常情況下,TCP要進行三次握手建立連接,四次揮手斷開連接。
在這裏插入圖片描述

注意:並不存在所謂的closed狀態

服務器的狀態變化:

closed–listen:服務器調用listen後進入listen狀態,等待客戶端連接

listen—SYN_RCVD:一旦監聽到連接請求SYN,就將該連接放入內核等待隊列中,並向客戶端發送SYN+ACK確認報文段

SYN_RCVD–ESTABLISHED :服務器一旦收到客戶端的確認報文,就進入該狀態,連接成功就可以讀寫數據了。

ESTABLISHED–CLOSE_WAIT:客戶端想向務器發送close請求。服務器收到FIN結束報文段,返回ACK確認報文段並進入CLOSE_WAIT;

CLOSE_WAIT—LAST_ACK: 進入CLOSED_WAIT後,服務器(處理完當前數據後)準備關閉連接, ,向客戶端發送FIN,此時等待最後一個ACK到來

LAST_ACK— CLOSED:最後一個ACK到達,徹底關閉連接。

客戶端狀態變化:

CLOSED–SYN_SENT:客戶端調connect,發送同步報文;

SYN_SENT–ESTABLiSHED: 服務器返回FIN+ACK;connect 成功。可以讀寫數據了

ESTABLISHED—FIN_WAIT1: 客戶端主動調用close函數,向服務器發送FIN;

FIN_WAIT1 —FIN_WAIT2:客戶端收到服務器發送回來的ACK,確認報文段。

FIN_WAIT2—TIME_WAIT:客戶端收到服務器發送的FIN結束報文段,收到,回覆LAST_ACK 。即最後一次ACK

TIME_WAIT–CLOSED:客戶端發送完LAST_ACK後等待2MSL;(防止最後一個ACK未到達,超時重傳)

爲什麼時間規定爲2MSL?

MSL是TCP報文的最大生存時間,2MS了能夠保證兩個傳輸方向上尚未被接收/遲到的報文段都已經消失,(防止服務器立即重啓,收到了上一個進程的的數據)。
同時2MSL也可以保證最後一個ACK可以到達,假如最後一個AC看丟失,因爲這是tcp連接還沒斷開,服務器會再發送一個FIN,這時客戶端進程雖然不在了,但tcp連接還在,仍然可以重發LAST——ACK ;

使用setsockopt() 函數可以設置socket,SO_REUSEADDR 爲1 ,表示可以穿件端口號相同,但IP地址不同的socket

int opt =1 ;
setsockopt(listenfd,SOL_SOCKET,SO_)

**在四次揮手中怎麼理解客戶端收到服務器的FIN時的

TIME——WAIT狀態**

做測試時,我們同時運行服務器和客戶端,關閉服務器,然後又迅速打開,就可以發現
bind error;

因爲,雖然server程序終止了,但是底層TCP協議層的連接還未徹底斷開,因此端口號,IP地址此時還在佔用,所以不能再次監聽同樣的server端口。

我們可以用netstat -apn命令查看一下當前端口號進程信息

TCP協議規定:主動斷開連接的一方要處於TIME_WAIT狀態,等待2*MSL時間後回到CLOSED狀態

MSL在RFC1122中規定爲2minutes,,各個操作系統實現不同,centos7默認配置60秒

可以通過
cat /proc/sys/net/ipv4/tcp_fin_timeout 查看
在這裏插入圖片描述
使用 setsockopt()函數可以設置產生port相同,但IP不同的 端口號

選項SO_REUSEADDR 爲1,表示允許port相同,但IP不同的socket;

eg:
int opt =1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

3:滑動窗口

實質 :一大段要發送的數據,收到ACK,滑動窗口就向後移動。

內核同時開闢了一段發送緩衝區來維護滑動窗 口,發送緩衝區記錄未應答的數據,若數據被應答,就從緩衝區刪掉。

作用 :提高吞吐量,提高傳輸效率
管理 :由內核維護

    1 批量發送數據
		
		2 **批量發送的數據量稱爲窗口大小 ,窗口越大,吞吐率越高,但一定要保證可靠性哦,所以不能無限大**。
		
		3 內核開闢一個發送緩衝區,保證沒有收到ACK的數據別被刪掉,隨時可以進行超時重傳,
		
		4 後邊的ACK能夠保證前邊的數據已經正確到達,所以前邊的ACK丟了有時也沒關係,這也意味着,好多條數據纔可能收到一條ACK ,所以這樣只會發保留髮送失敗數據的ACK,所以這稱爲**快速重傳**。

正確數據放在內核的接收緩衝區中,傳送失敗的數據就會不斷收到相應字節序的ACK,這種機制被稱爲高速重發機制-----或者 快重傳機制。

	最後,接收端怎麼將滑動窗口大小告知發送端呢?

	在TCP報文首部,有一個16位的窗口字段,存放了窗口大小的信息。那麼問題又來了,16位表示最大數據2^16次方,那麼滑動窗口最大隻有64K嗎?
	
	並不是,TCP首部40字節選項中還包括一個窗口擴大因子M,實際窗口的大小爲窗口字段左移M位;

5:流量控制機制:

		設置原因:
		接收端處理數據的能力是有限的,假如發送端發送數據太快,導致接收端不能及時處理,就會使接收端緩衝區逐漸變滿,再傳輸數據就會發生丟包。
		
		是什麼:
		因此TCP協議支持根據接收端處理數據的能力,決定發送端的發送速度,這個機制稱爲流量控制機制

		如果接收緩衝區滿了,就會使滑動窗口大小爲0,這是發送方就不會發送數據了,然後發送端定期發送一個窗口探測數據端,獲取接收端大的窗口大小

	接收緩衝區的空餘空間大小用來衡量接收端的處理性能。(細想,空間越大,不就是接收端處理的越快嗎?)
	TCP協議中有一個窗口大小字段,通過ACK端通知發送端

6:擁塞控制:

引入原因

	雖然TCP有滑動窗口這個寶貝,能高效提高傳輸效率,但是,網絡上有很多計算機,當前的網絡狀態可能已經很糟糕了,這時若還是一下發送大量數據,對本就糟糕的網絡來說無意雪上加霜了。

因此,TCP引入慢啓動機制,先發一丟丟數據探探路,摸摸當前的網絡狀態,再決定按多大速率發送數據。

在這裏插入圖片描述

像不像戀愛中小情侶的感覺呢?
熱戀,吵架,和好,熱戀……

1 怎麼來判斷是否擁塞呢?

     根據丟包的量來判定
     **少量丟包認爲超時重傳,大量丟包認爲網絡擁塞**

2  慢開始:

	1 開始時設置一個比較小的窗口來發送數據。
	2 若沒發生丟包,窗口大小指數增長,
	3 當到達一個指定的閾值時,變爲線性增長
	4 這樣到達一定大小時,就會發生丟包,這時立馬將窗口大小設爲一個特別小的值(1),閾值乘法減小(*0.5)
	  然後再重新慢開始循環

	
			

那麼問題來了?窗口大小怎麼控制呢?

答:擁塞控制 + 流量控制 
TCP首部的 16位窗口大小 說明滑動窗口的基礎大小是65535 同時 ,首部還包含一個M因子,他決定滑動窗口最大值可以 向右移動幾位,2進制哦。

擁塞控制歸根到底還是 TCP協議爲了儘可能快的把數據傳輸過去,又要儘可能保證網絡壓力不要太大的折中方案

當TCP通信開始時,吞吐量會逐漸上升,一旦網絡發生擁塞,吞吐量 立刻急劇下降。

7:延時應答

	爲什麼要延時應答?
	答:因爲處理器處理數據的能力可能很大,若不延時應答,一次接收的數據可能還不夠服務器處理時開胃菜,所以延時應答
	
	延時應答控制方法:	
		1:數量條件:每收幾個包就應答一次
		2:時間條件,每過多久應答一次

	具體的數量和超時時間,根據操作系統而定,一般數量取2,超時時間爲200ms。

8:捎帶應答

eg:
How are you
i’m fine thanks and you

捎帶應答:可能將四次揮手變爲三次揮手。

	在延遲應答的基礎上,服務器有可能將在收到FIN斷開連接時,將  ACK 和 FIN一起發送過去,這時四次揮手變成三次揮手

	TCP協議是操作系統內核實現的,不同的系統實現細節可能存在細微差異,
	這時fiddler抓包就不靠譜了,fiddler只能抓HTTP協議    
	wireshark可以	抓TCP協議的數據包

9:面向字節流

TCP傳輸時可以將一個完整的數據包分多次發送或接收。

10:粘包問題

   由面向字節流傳輸方式導致,但應用程序需要一次取出一個完整的數據包,怎麼來解決這個問題?
   
	       我們從應用層的角度來解決這個問題,只需要能夠確定數據包的邊界就可以了。
	       
		確定包的邊界的方案: 1	分隔符    2 指定長度

	UDP會發生粘包問題嗎?
	因爲UDP是一個數據包一個數據包的提交數據,因此不可能發生提交半了包的情況,也就不可能出現粘包問題

連接異常:

	1 進程終止(正常----先關閉客戶端)
	2 重啓(相當於開始菜單的重啓:即既定流程重啓)
	3 機器斷電/網線斷掉:接收端認爲連接還存在,很久了還麼收到數據,就會超時重傳,  重傳次數過多服務器復位RST (reset)

 4內核自己也內置了一個保活定時器。保活定時器會定期發送一個詢問信號,詢問對方(客戶端)是否存在。不存在就釋放連接

TCP 和 UDP 的對比

	1TCP使用在可靠傳輸的場合
	
	2UDP傳輸速度高,也可以使用在傳輸環境安全性本身就高的環境,達到可靠傳輸的目的。
	
	3數據包大的話只能使用TCP, 因爲 UDP最大包只用64K即16位UDP最大長度2^16
	
	4**如果要廣播的話,只能用UDP**,不能用TCP。只有UDP可以將物理IP最後的幾位全設置爲1,代表廣播地址。

	5TCP 面向字節流有粘包問題 UDP面向數據報,不存在粘包問題

6  UDP不存在真實的的發送緩衝區,只有內核創建接收緩衝區,而TCP都有。

Listen的第二個參數理解

我們可以去掉服務器程序裏面的accept。同時打開多個客戶端連接服務器,再查看狀態netstat,就會發現一些現象。

Linux內核協議棧爲tcp連接管理使用了兩個隊列:
半連接隊列:保存處於半連接狀態SYN-SENT和SYN-RCVD狀態的請求

全連接對立:連接成功的處於established的請求,即accept隊列,這個隊列受accept影響。全連接對=隊列的長度爲 listen第二個參數的+1

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