TCP/IP 網絡基礎(三)傳輸層

網絡層爲通訊搭建好了基礎架構,但對於應用程序來講,它還是「不可用」的。相似地,即便各級鐵路公路能通到全國的任何地方,但若是沒有快遞公司,你怎麼寄東西?傳輸層就是給須要使用網絡傳輸的應用程序直接使用的協議,也只有它提供了編程接口,即套接字。算法

傳輸層

TCP/IP在傳輸層的主要協議就是TCP和UDP。在這一層,它們引入了兩個新的概念。編程

端口

網絡層只有地址。但實際上,同一個地址(主機)上還有不一樣的進程。爲了區分這些進程就引入了端口。協議+IP+端口才能惟必定位到一個目標應用。
HTTP、FTP等上層協議使用的端口號都是固定的,這些叫作知名端口號,由0到1023佔據。應用程序應該避免使用這些端口號。服務器

客戶端/服務器

雖然通訊的兩個實體應該是對等的,但必然有一個要先發出第一個請求,它就是客戶端。另外一個就是服務器。而做爲服務器,應該在第一個請求到來以前就啓動並準備好,所以一般有個守護進程。也就是說,服務器監聽一個或多個客戶端的消息(TCP請求或UDP數據報),而客戶端先開口說話。網絡

UDP

即用戶報文協議,它簡單地封裝了IP層的功能,提供無鏈接的通訊服務。UDP可能會出現丟包、亂序,也沒法處理網絡擁堵。而這些處理只能由使用它的上層應用實現。總而言之,UDP就是個輕量快速的協議,它每每應用於如下幾個方面:架構

  • 包總量不多的通訊(如DNS,SNMP等)。
  • 音視頻等對效率要求高而又對少許丟包不敏感的通訊。

TCP

TCP則是一種至關可靠的協議。它是面向鏈接的,而且有丟包重發,亂序整理,擁塞控制等功能。下面咱們來分別介紹它是怎麼作的。socket

首先,首部校驗和這個技術確定是有的。從物理層、數據鏈路層、網絡層,甚至UDP都是具有的。只有它能防止內容出錯。spa

鏈接管理

就是幾乎家喻戶曉的三次握手和四次揮手。上圖:
3 way handshake3d

三次握手簡單來講就是客戶端問服務端在嗎?服務端回答我在,收到吱一聲。客戶端:吱。而後鏈接就創建了。固然中間有一些商量MTU(最大傳輸單元),同步發送和ACK序號的過程,略去不表。再看四次揮手:
4 way wavehand視頻

四次揮手的過程至關於你和老闆 1 on 1 結束時的場景。開始是大家你一句我一句,而後你對老闆說:我沒話了,你呢?老闆:收到。可是我還有幾件事要交代,bla bla... 最後,老闆:好了我也說完了,你能夠滾了。你:好的。blog

解決亂序和丟包

TCP爲每段發送的數據都標上相對開頭的字節偏移,接收端收到後則要響應一個ACK消息,告訴發送端本身收到了哪段數據。發送端發送了一段數據後遲遲沒有收到確認消息,就會重發。而接收端反正有各個消息的序號,即便到達的數據亂序,也能正確地處理。若是收到重複的數據,就直接丟棄。這種技術就稱爲確認-重傳機制。
圖片描述

超時檢測是經過定時器實現的,而定時器的時常不是固定的,而是根據估算的往返時間(RTT)動態調整。這也是TCP的NB之處。

滑動窗口

你覺得確認-重發機制就這麼簡單?真實的情形遠比上圖的複雜。TCP採用滑動窗口技術來實現其收發機制。
TCP鏈接的每一端都維護了一個接收窗口。它的意思就是所指望收到的下一段數據的序號範圍。當數據到達時,序號超出這個窗口的都被丟棄。而後若是窗口的前幾個字節已經收到了,就通知應用程序讀取,再向後滑動窗口,而後發送ACK消息通知對端下一個期待的序號。
接收窗口

如上圖,(A)表示但願接收到的下一個字節序號是4,而且能夠接受9個字節。(B)表示收到了4,5,6,7幾個字節後,接收窗口向後移動了4個字節,而且發送的ACK將代表它接下來指望收到序號8.

同理,發送端也會維護一個發送窗口,而它又分爲兩部分:已發送但未收到確認的字節,和能夠發送但未發送的字節。
發送窗口

如上圖,字節1~3已經收到了確認消息。(A)表示當前的發送窗口。在字節4~7發送以後,被確認以前,發送窗口如(B)所示。此時,TCP還能夠發送8~12而無須等待對方的ACK。但發送這些字節以後,定時器就會啓動,若是超時以前尚未收到ACK,這段數據就會重發。
(C)表示字節4~7收到確認後發送窗口後移。

經過滑動窗口,能夠解決簡單的發送-應答機制每次只能發送一段數據,等待太多,效率過低的問題。如今的通訊情況以下:
圖片描述

流控制和擁塞控制

流控制就是考慮接受端的接收能力,不要發的太快,否則接收不過來也是白白浪費網絡流量。方法就是接收方把本身的接收窗口告訴發送方。

TCP採用慢啓動,最終會趨向於佔滿帶寬。具體算法再也不研究。

套接字

套接字即Socket Api,它起初發源於Unix,後來又被移植到Windows上成爲Winsock。也就是說,六合以內,它是網絡層編程的惟一接口。
本人目前沒有直接對套接字編程的需求,在此只做簡單介紹。

對服務器程序來講,基本的操做是先得到socket結構體,接着調用bind綁定地址和端口,而後就監聽在端口上。這個過程阻塞。當有鏈接進來時,程序繼續,調用accept得到對方的socket,而後就能夠調用recv和send進行通訊。

對客戶端程序來講,基本的操做是先得到socket結構體,再調用connect鏈接服務器,成功後調用recv和send進行通訊。

套接字API封裝了前面講解的滑動窗口等各類機制,對程序來講,只能讀取到數據流。由於TCP就是個流協議,沒法控制數據段到達對端的方式。一樣的,應用程序把數據發送給底層後,也沒法控制數據如何被髮送,如被打包仍是分拆。
所以,讀取這種字節流時,若是是定長報文就很好辦,每次讀取固定字節便可。而若是報文內容是可變的,則每每採用這樣一種方式:在每條報文前面加上一個首部,其中包含本記錄的長度。這樣接收端就能夠分兩次讀取報文。第一次先用定長方式讀取首部,取出長度,而後第二次讀取所有報文。
record
這讓我想起了之前似懂非懂地修改過的公司某產品的通訊協議…

TCP是萬能的嗎?

TCP徹底可靠,不須要應用程序考慮任何事情?固然沒有這麼神奇的事情。最簡單地,若是兩個端點通訊不可達,TCP就毫無辦法。另外,應用程序是針對套接字編程,也要考慮對端的特殊輸入、不友好動做等錯誤處理。具體可見《TCP/IP高效編程》的技巧9,11.

總結與感悟

網絡協議不一樣於咱們在一臺機器上的編程約定和規範——後者老是至關可控的。舉個極端的例子,你在 Word 程序裏寫了個你的銀行密碼,而後你不想再讓第二我的知道。你能夠刪除這個字符串,或者刪除文檔,甚至在緊急狀況下把電腦砸了。究其根源,是你從物理上擁有這臺電腦。而網絡協議,你把一個數據包發出去,而後事情就脫離了你的控制。剩下的任務就依賴於別的組織、我的、設備能正常盡職的工做,履行交付的承諾。這裏面大量依賴了約定和信任。固然,任何一個不能遵照這些協議的公司的產品,也不可能有消費者會買單。想想,咱們每月付給運營商一些網費,就能夠無限量地傳輸任何數據到任何地址,這不是一個神奇的事情嗎?

相關文章
相關標籤/搜索