【软件通信协议】1. 详细解析TCP/IP通信协议
1. TCP/IP協(xié)議簡介
? ? ? ? Transmission Control Protocol/Internet Protocol的簡寫,中譯名為傳輸控制協(xié)議/因特網(wǎng)互聯(lián)協(xié)議,又名網(wǎng)絡(luò)通訊協(xié)議,是Internet最基本的協(xié)議、Internet國際互聯(lián)網(wǎng)絡(luò)的基礎(chǔ),由網(wǎng)絡(luò)層的IP協(xié)議和傳輸層的TCP協(xié)議組成。TCP/IP 定義了電子設(shè)備如何連入因特網(wǎng),以及數(shù)據(jù)如何在它們之間傳輸?shù)臉?biāo)準(zhǔn)。協(xié)議采用了4層的層級結(jié)構(gòu),每一層都呼叫它的下一層所提供的協(xié)議來完成自己的需求。通俗而言:TCP負(fù)責(zé)發(fā)現(xiàn)傳輸?shù)膯栴},一有問題就發(fā)出信號,要求重新傳輸,直到所有數(shù)據(jù)安全正確地傳輸?shù)侥康牡亍6鳬P是給因特網(wǎng)的每一臺聯(lián)網(wǎng)設(shè)備規(guī)定一個地址(互動百科的定義)。
2. TCP/IP與ISO/OSI分層比較
?
TCP/IP協(xié)議族按照層次由上到下,層層包裝。
應(yīng)用層:
 ? ? ? ? 向用戶提供一組常用的應(yīng)用程序,比如電子郵件、文件傳輸訪問、遠(yuǎn)程登錄等。遠(yuǎn)程登錄TELNET使用TELNET協(xié)議提供在網(wǎng)絡(luò)其它主機(jī)上注冊的接口。TELNET會話提供了基于字符的虛擬終端。文件傳輸訪問FTP使用FTP協(xié)議來提供網(wǎng)絡(luò)內(nèi)機(jī)器間的文件拷貝功能。
? ? ? ? 應(yīng)用層做為 TCP/IP 協(xié)議的最高層級,對于我們移動開發(fā)來說,是接觸最多的。
運行在TCP協(xié)議上的協(xié)議:
運行在UDP協(xié)議上的協(xié)議:
其他:
傳輸層:
 ? ? ? ? 提供應(yīng)用程序間的通信。其功能包括:一、格式化信息流;二、提供可靠傳輸。為實現(xiàn)后者,傳輸層協(xié)議規(guī)定接收端必須發(fā)回確認(rèn),并且假如分組丟失,必須重新發(fā)送。
網(wǎng)絡(luò)層?:
? ? ? ? 負(fù)責(zé)相鄰計算機(jī)之間的通信。其功能包括三方面。
 ? ? ? ? a、處理來自傳輸層的分組發(fā)送請求,收到請求后,將分組裝入IP數(shù)據(jù)報,填充報頭,選擇去往信宿機(jī)的路徑,然后將數(shù)據(jù)報發(fā)往適當(dāng)?shù)木W(wǎng)絡(luò)接口。
? ? ? ? b、處理輸入數(shù)據(jù)報:首先檢查其合法性,然后進(jìn)行尋徑--假如該數(shù)據(jù)報已到達(dá)信宿機(jī),則去掉報頭,將剩下部分交給適當(dāng)?shù)膫鬏攨f(xié)議;假如該數(shù)據(jù)報尚未到達(dá)信宿,則轉(zhuǎn)發(fā)該數(shù)據(jù)報。
? ? ? ? c、處理路徑、流控、擁塞等問題。
? ? ? ? 那么網(wǎng)絡(luò)層是如何做物理地址與邏輯地址之間的轉(zhuǎn)換呢?所以就涉及到如下的ip、地址解析協(xié)議ARP、子網(wǎng)的定義。
2.1 IP(下面的介紹都是基于 IPv4 進(jìn)行的)
? ? ? ? TCP/IP 協(xié)議網(wǎng)絡(luò)上的每一個網(wǎng)絡(luò)適配器都有一個唯一的 IP 地址.
? ? ? ? IP 地址是一個 32 位的地址,這個地址通常分成 4 端,每 8 個二進(jìn)制為一段,但是為了方便閱讀,通常會將每段都轉(zhuǎn)換為十進(jìn)制來顯示,比如大家非常熟悉的 192.168.0.1
IP 地址分為兩個部分:
但是具體哪部分屬于網(wǎng)絡(luò) ID,哪些屬于主機(jī) ID 并沒有規(guī)定.
因為有些網(wǎng)絡(luò)是需要很多主機(jī)的,這樣的話代表主機(jī) ID 的部分就要更多,但是有些網(wǎng)絡(luò)需要的主機(jī)很少,這樣主機(jī) ID 的部分就應(yīng)該少一些.
絕大部分 IP 地址屬于以下幾類
? ? ? ? A 類地址:IP 地址的前 8 位代表網(wǎng)絡(luò) ID ,后 24 位代表主機(jī) ID。
? ? ? ? B 類地址:IP 地址的前 16 位代表網(wǎng)絡(luò) ID ,后 16 位代表主機(jī) ID。
? ? ? ? C 類地址:IP 地址的前 24 位代表網(wǎng)絡(luò) ID ,后 8 位代表主機(jī) ID。
這里能夠很明顯的看出 A 類地址能夠提供出的網(wǎng)絡(luò) ID 較少,但是每個網(wǎng)絡(luò)可以擁有非常多的主機(jī)。但是我們怎么才能看出一個 IP 地址到底是哪類地址呢?
如果 32 位的 IP 地址以 0 開頭,那么它就是一個 A 類地址。
如果 32 位的 IP 地址以 10 開頭,那么它就是一個 B 類地址。
如果 32 位的 IP 地址以 110 開頭,那么它就是一個 C 類地址。
那么轉(zhuǎn)化為十進(jìn)制(四段)的話,我們就能以第一段中的十進(jìn)制數(shù)來區(qū)分 IP 地址到底是哪類地址了。
?
注意:
? ? ? ? 全是 0 的主機(jī) ID 代表網(wǎng)絡(luò)本身,比如說 IP 地址為 130.100.0.0 指的是網(wǎng)絡(luò) ID 為130.100 的 B 類地址。
? ? ? ? 全是 1 的主機(jī) ID 代表廣播,是用于向該網(wǎng)絡(luò)中的全部主機(jī)方法消息的。 IP 地址為 130.100.255.255 就是網(wǎng)絡(luò) ID 為 130.100 網(wǎng)絡(luò)的廣播地址(二進(jìn)制 IP 地址中全是 1 ,轉(zhuǎn)換為十進(jìn)制就是 255 )
? ? ? ? 以十進(jìn)制 127 開頭的地址都是環(huán)回地址。目的地址是環(huán)回地址的消息,其實是由本地發(fā)送和接收的。主要是用于測試 TCP/IP 軟件是否正常工作。我們用 ping 功能的時候,一般用的環(huán)回地址是 127.0.0.1
2.2 地址解析協(xié)議ARP
? ? ? ? 在網(wǎng)絡(luò)通信過程中, 源主機(jī)的應(yīng)用程序只知道目的應(yīng)用程序的IP地址, 并不知道對方主機(jī)的硬件地址, 所以在數(shù)據(jù)發(fā)送之前, 需要先找到目標(biāo)及其的硬件地址, 這就是ARP協(xié)議所起的作用了。
? ? ? ? 每次在建立連接之前, 會在本地網(wǎng)絡(luò)廣播發(fā)送目的IP地址, 所有機(jī)器都會受到該請求, 目的機(jī)器發(fā)現(xiàn)該請求中的IP地址跟自己一樣, 就把自己的硬件地址返回回去, 否則忽略該請求。
? ? ? ? 一般來說, 每臺機(jī)器都維護(hù)的有一個ARP緩存表, 存儲了近期的IP地址和硬件地址的映射關(guān)系, 可以用arp -a命令來查看緩存表中內(nèi)容。
? ? ? ? 如果目的機(jī)器和本機(jī)器不在同一個網(wǎng)段之內(nèi)的話, 會將數(shù)據(jù)發(fā)送給網(wǎng)關(guān)來處理, 一般網(wǎng)關(guān)就是路由器, 此時網(wǎng)關(guān)會進(jìn)行IP路由, 將ARP請求發(fā)送到目的網(wǎng)絡(luò)地址, 然后再依次將應(yīng)答返回給該發(fā)起請求的機(jī)器。
2.3 子網(wǎng)
? ? ? ? 前面提到了 IP 地址的分類,但是對于 A 類和 B 類地址來說,每個網(wǎng)絡(luò)下的主機(jī)數(shù)量太多了,那么網(wǎng)絡(luò)的傳輸會變得很低效,并且很不靈活。比如說 IP地址為 100.0.0.0 的 A 類地址,這個網(wǎng)絡(luò)下的主機(jī)數(shù)量超過了 1600 萬臺。
? ? ? ? 所以子網(wǎng)掩碼的出現(xiàn)就是為了解決這樣的問題。
? ? ? ? 我們先回顧一下之前如何區(qū)分主機(jī) IP 和網(wǎng)絡(luò) IP 的。
? ? ? ? 以 A 類地址 99.10.10.10 為例,前 8 位是網(wǎng)絡(luò) IP ,后 24 位是主機(jī) IP 。(如下圖)
? ? ? ? 子網(wǎng)掩碼也是一個 32 為的二進(jìn)制數(shù),也可以用四個十進(jìn)制數(shù)來分段,他的每一位對應(yīng)著 IP 地址的相應(yīng)位置,數(shù)值為 1 時代表的是非主機(jī)位,數(shù)值為 0 時代表是主機(jī)位。
? ? ? ? 由表格可以很清晰的看出,網(wǎng)絡(luò) IP 仍是由之前的分類來決定到底是多少位,主機(jī) IP 則是由子網(wǎng)掩碼值為 0 的位數(shù)來決定,剩下的則是子網(wǎng) IP
網(wǎng)絡(luò)接口層:
 ? ? ? ? 這是TCP/IP軟件的最低層,負(fù)責(zé)接收IP數(shù)據(jù)報并通過網(wǎng)絡(luò)發(fā)送之,或者從網(wǎng)絡(luò)上接收物理幀,抽出IP數(shù)據(jù)報,交給IP層,主要是指物理層次的一些接口,比如電纜等。
注:第二章轉(zhuǎn)載自https://blog.csdn.net/yulyu/article/details/69062288
3. TCP/IP報文格式
IP協(xié)議數(shù)據(jù)包格式如下:
其中字段的含義:
TCP報文格式如下:
16位源端口號:16位的源端口中包含初始化通信的端口。源端口和源IP地址的作用是標(biāo)識報文的返回地址。
16位目的端口號:16位的目的端口域定義傳輸?shù)哪康摹_@個端口指明報文接收計算機(jī)上的應(yīng)用程序地址接口。
32位序號:32位的序列號由接收端計算機(jī)使用,重新分段的報文成最初形式。當(dāng)SYN出現(xiàn),序列碼實際上是初始序列碼(Initial Sequence Number,ISN),而第一個數(shù)據(jù)字節(jié)是ISN+1。這個序列號(序列碼)可用來補(bǔ)償傳輸中的不一致。
32位確認(rèn)序號:32位的序列號由接收端計算機(jī)使用,重組分段的報文成最初形式。如果設(shè)置了ACK控制位,這個值表示一個準(zhǔn)備接收的包的序列碼。
4位首部長度:4位包括TCP頭大小,指示何處數(shù)據(jù)開始。
保留(6位):6位值域,這些位必須是0。為了將來定義新的用途而保留。
標(biāo)志:6位標(biāo)志域。表示為:緊急標(biāo)志、有意義的應(yīng)答標(biāo)志、推、重置連接標(biāo)志、同步序列號標(biāo)志、完成發(fā)送數(shù)據(jù)標(biāo)志。按照順序排列是:URG、ACK、PSH、RST、SYN、FIN。
16位窗口大小:用來表示想收到的每個TCP數(shù)據(jù)段的大小。TCP的流量控制由連接的每一端通過聲明的窗口大小來提供。窗口大小為字節(jié)數(shù),起始于確認(rèn)序號字段指明的值,這個值是接收端正期望接收的字節(jié)。窗口大小是一個16字節(jié)字段,因而窗口大小最大為65535字節(jié)。
16位校驗和:16位TCP頭。源機(jī)器基于數(shù)據(jù)內(nèi)容計算一個數(shù)值,收信息機(jī)要與源機(jī)器數(shù)值 結(jié)果完全一樣,從而證明數(shù)據(jù)的有效性。檢驗和覆蓋了整個的TCP報文段:這是一個強(qiáng)制性的字段,一定是由發(fā)送端計算和存儲,并由接收端進(jìn)行驗證的。
16位緊急指針:指向后面是優(yōu)先數(shù)據(jù)的字節(jié),在URG標(biāo)志設(shè)置了時才有效。如果URG標(biāo)志沒有被設(shè)置,緊急域作為填充。加快處理標(biāo)示為緊急的數(shù)據(jù)段。
選項:長度不定,但長度必須為1個字節(jié)。如果沒有選項就表示這個1字節(jié)的域等于0。
數(shù)據(jù):該TCP協(xié)議包負(fù)載的數(shù)據(jù)。
在上述字段中,6位標(biāo)志域的各個選項功能如下。
4. TCP三次握手
? ? ? ? 所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務(wù)端總共發(fā)送3個包以確認(rèn)連接的建立。在socket編程中,這一過程由客戶端執(zhí)行connect來觸發(fā),整個流程如下圖所示:
(1)第一次握手:Client將標(biāo)志位SYN置為1,隨機(jī)產(chǎn)生一個值seq=J,并將該數(shù)據(jù)包發(fā)送給Server,Client進(jìn)入SYN_SENT狀態(tài),等待Server確認(rèn)。
(2)第二次握手:Server收到數(shù)據(jù)包后由標(biāo)志位SYN=1知道Client請求建立連接,Server將標(biāo)志位SYN和ACK都置為1,ack=J+1,隨機(jī)產(chǎn)生一個值seq=K,并將該數(shù)據(jù)包發(fā)送給Client以確認(rèn)連接請求,Server進(jìn)入SYN_RCVD狀態(tài)。
(3)第三次握手:Client收到確認(rèn)后,檢查ack是否為J+1,ACK是否為1,如果正確則將標(biāo)志位ACK置為1,ack=K+1,并將該數(shù)據(jù)包發(fā)送給Server,Server檢查ack是否為K+1,ACK是否為1,如果正確則連接建立成功,Client和Server進(jìn)入ESTABLISHED狀態(tài),完成三次握手,隨后Client與Server之間可以開始傳輸數(shù)據(jù)了。
簡單來說,就是
? ? ? ? 1、建立連接時,客戶端發(fā)送SYN包(SYN=i)到服務(wù)器,并進(jìn)入到SYN-SEND狀態(tài),等待服務(wù)器確認(rèn)
? ? ? ? 2、服務(wù)器收到SYN包,必須確認(rèn)客戶的SYN(ack=i+1),同時自己也發(fā)送一個SYN包(SYN=k),即SYN+ACK包,此時服務(wù)器進(jìn)入SYN-RECV狀態(tài)
? ? ? ? 3、客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)報ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手,客戶端與服務(wù)器開始傳送數(shù)據(jù)。
SYN攻擊:
? ? ? ? 在三次握手過程中,Server發(fā)送SYN-ACK之后,收到Client的ACK之前的TCP連接稱為半連接(half-open connect),此時Server處于SYN_RCVD狀態(tài),當(dāng)收到ACK后,Server轉(zhuǎn)入ESTABLISHED狀態(tài)。SYN攻擊就是Client在短時間內(nèi)偽造大量不存在的IP地址,并向Server不斷地發(fā)送SYN包,Server回復(fù)確認(rèn)包,并等待Client的確認(rèn),由于源地址是不存在的,因此,Server需要不斷重發(fā)直至超時,這些偽造的SYN包將產(chǎn)時間占用未連接隊列,導(dǎo)致正常的SYN請求因為隊列滿而被丟棄,從而引起網(wǎng)絡(luò)堵塞甚至系統(tǒng)癱瘓。SYN攻擊時一種典型的DDOS攻擊,檢測SYN攻擊的方式非常簡單,即當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機(jī)的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現(xiàn)形:
#netstat -nap | grep SYN_RECV
5. TCP四次揮手
? ? ? ? 所謂四次揮手(Four-Way Wavehand)即終止TCP連接,就是指斷開一個TCP連接時,需要客戶端和服務(wù)端總共發(fā)送4個包以確認(rèn)連接的斷開。在socket編程中,這一過程由客戶端或服務(wù)端任一方執(zhí)行close來觸發(fā),整個流程如下圖所示:
? ? ? ? 由于TCP連接時全雙工的,因此,每個方向都必須要單獨進(jìn)行關(guān)閉,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后,發(fā)送一個FIN來終止這一方向的連接,收到一個FIN只是意味著這一方向上沒有數(shù)據(jù)流動了,即不會再收到數(shù)據(jù)了,但是在這個TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動關(guān)閉,而另一方則執(zhí)行被動關(guān)閉,上圖描述的即是如此。
? ? ? ? (1)第一次揮手:Client發(fā)送一個FIN,用來關(guān)閉Client到Server的數(shù)據(jù)傳送,Client進(jìn)入FIN_WAIT_1狀態(tài)。
? ? ? ? (2)第二次揮手:Server收到FIN后,發(fā)送一個ACK給Client,確認(rèn)序號為收到序號+1(與SYN相同,一個FIN占用一個序號),Server進(jìn)入CLOSE_WAIT狀態(tài)。
? ? ? ? (3)第三次揮手:Server發(fā)送一個FIN,用來關(guān)閉Server到Client的數(shù)據(jù)傳送,Server進(jìn)入LAST_ACK狀態(tài)。
? ? ? ? (4)第四次揮手:Client收到FIN后,Client進(jìn)入TIME_WAIT狀態(tài),接著發(fā)送一個ACK給Server,確認(rèn)序號為收到序號+1,Server進(jìn)入CLOSED狀態(tài),完成四次揮手。
為什么建立連接是三次握手,而關(guān)閉連接卻是四次揮手呢?
? ? ? ? 這是因為服務(wù)端在LISTEN狀態(tài)下,收到建立連接請求的SYN報文后,把ACK和SYN放在一個報文里發(fā)送給客戶端。而關(guān)閉連接時,當(dāng)收到對方的FIN報文時,僅僅表示對方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),己方也未必全部數(shù)據(jù)都發(fā)送給對方了,所以己方可以立即close,也可以發(fā)送一些數(shù)據(jù)給對方后,再發(fā)送FIN報文給對方來表示同意現(xiàn)在關(guān)閉連接,因此,己方ACK和FIN一般都會分開發(fā)送。
為什么TIME_WAIT狀態(tài)需要經(jīng)過2MSL(最大報文段生存時間)才能返回到CLOSE狀態(tài)?
原因有二:
 ? ? ? ? 一、保證TCP協(xié)議的全雙工連接能夠可靠關(guān)閉
 ? ? ? ? 二、保證這次連接的重復(fù)數(shù)據(jù)段從網(wǎng)絡(luò)中消失
? ? ? ? 先說第一點,如果Client直接CLOSED了,那么由于IP協(xié)議的不可靠性或者是其它網(wǎng)絡(luò)原因,導(dǎo)致Server沒有收到Client最后回復(fù)的ACK。那么Server就會在超時之后繼續(xù)發(fā)送FIN,此時由于Client已經(jīng)CLOSED了,就找不到與重發(fā)的FIN對應(yīng)的連接,最后Server就會收到RST而不是ACK,Server就會以為是連接錯誤把問題報告給高層。這樣的情況雖然不會造成數(shù)據(jù)丟失,但是卻導(dǎo)致TCP協(xié)議不符合可靠連接的要求。所以,Client不是直接進(jìn)入CLOSED,而是要保持TIME_WAIT,當(dāng)再次收到FIN的時候,能夠保證對方收到ACK,最后正確的關(guān)閉連接。
? ? ? ? 再說第二點,如果Client直接CLOSED,然后又再向Server發(fā)起一個新連接,我們不能保證這個新連接與剛關(guān)閉的連接的端口號是不同的。也就是說有可能新連接和老連接的端口號是相同的。一般來說不會發(fā)生什么問題,但是還是有特殊情況出現(xiàn):假設(shè)新連接和已經(jīng)關(guān)閉的老連接端口號是一樣的,如果前一次連接的某些數(shù)據(jù)仍然滯留在網(wǎng)絡(luò)中,這些延遲數(shù)據(jù)在建立新連接之后才到達(dá)Server,由于新連接和老連接的端口號是一樣的,又因為TCP協(xié)議判斷不同連接的依據(jù)是socket pair,于是,TCP協(xié)議就認(rèn)為那個延遲的數(shù)據(jù)是屬于新連接的,這樣就和真正的新連接的數(shù)據(jù)包發(fā)生混淆了。所以TCP連接還要在TIME_WAIT狀態(tài)等待2倍MSL,這樣可以保證本次連接的所有數(shù)據(jù)都從網(wǎng)絡(luò)中消失。
注:以上轉(zhuǎn)載自:https://www.jianshu.com/p/ef892323e68f
6. TCP LinuxC編程CS模型
客戶端步驟:
? ? ? ? 1、創(chuàng)建套接字
? ? ? ? 2、向服務(wù)器發(fā)送連接請求(connect)
? ? ? ? 3、通信(send/recv)
? ? ? ? 4、關(guān)閉套接字
服務(wù)器端步驟:
? ? ? ? 1、創(chuàng)建用于監(jiān)聽的套接字(socket)
? ? ? ? 2、將套接字綁定到本地地址和端口上(bind)
? ? ? ? 3、將套接字設(shè)為監(jiān)聽模式(listen)
? ? ? ? 4、等待客戶請求(accept),此處要不斷的調(diào)用accept
? ? ? ? 5、通信(send/receive),完成后返回4
? ? ? ? 6、關(guān)閉套接字(closesocket)
?
基于TCP的CS模型Linux C代碼實現(xiàn)請移步github:
https://github.com/ZhenhuaWei/Linux-C-Demo.git
?
總結(jié)
以上是生活随笔為你收集整理的【软件通信协议】1. 详细解析TCP/IP通信协议的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 11.9 至 11.17 四道典型题记录
- 下一篇: tipask 3.5 出错get_cla
