前言:網絡知識很是的重要,若是你不是作程序的,那麼一些網絡常識仍是得知道的;而作程序的,就更不用說了,不只須要瞭解一些網絡知識,仍是知道其原理,若是不瞭解原理,不敢說他不是程序員,可是總缺了點意思,就像去北京沒去過長城同樣。程序員
網絡原理系列文章:瀏覽器
1、五分鐘瞭解網絡鏈接(已完成)服務器
2、收發數據的原理(上)(已完成)網絡
3、收發數據的原理(下)(已完成)併發
4、收發數據的番外篇(未完成)socket
上一篇五分鐘瞭解網絡鏈接講了網絡鏈接的大概流程,而且文末講到客戶端委託協議棧收發數據能夠總結爲四步:tcp
一、建立套接字(建立套接字階段)post
二、將管道鏈接到服務器端的套接字上(鏈接階段)操作系統
三、收發數據(通訊階段)3d
四、斷開管道並刪除套接字(斷開階段)
本文會對前兩個步驟展開描述,後面兩個步驟,下一篇文章介紹,敬請關注!因爲網絡知識點很是繁雜,讀者請沉住氣閱讀此文,我儘量詳細介紹,儘量的不那麼枯燥,因此本文介紹也有側重點。讀完本文,你可能會對一些知識恍然大悟,哦,原來是這樣啊!好了,廢話很少說,直接進入主題。
上面是協議棧的內部結構。分爲接個部分。上面部分會向下面的部分委派工做。
應用程序的下面是Socket庫,其中包括解析器,解析器向DNS服務器發出查詢,它的工做過程咱們在上一篇已經介紹過了。
再下面就是操做系統內部了,其中包括協議棧。協議棧的上半部分有兩塊,分別是負責用TCP協議收發數據的部分和負責用UDP協議收發數據的部分,它們會接受應用程序的委託執行收發數據的操做。關於TCP和UDP,會在後面文章講解,目前只要知道像瀏覽器、郵件等通常的應用程序、QQ文件傳輸都是使用TCP收發數據的,而像DNS查詢、QQ語音 、QQ視頻等收發較短的控制數據的時候則使用UDP。
協議棧的下半部分是利用IP協議控制網絡包收發數據的部分,在互聯網中發送數據,須要將數據分紅一個個小的網絡包,而後將網絡包發送給通訊對象就是由IP負責的。另外,ICMP用於錯誤提示以及各類控制消息,ARP則是用於查詢IP相應的以太網MAC地址。如今只須要大概知道這個名詞,後面纔會細講。
IP下面是驅動程序負責控制網卡硬件,最下面的網卡則是負責完成實際的收發操做——對網線中的信號執行發送和接受操做。
實際上套接字並沒存在實體,只是一個概念。在協議棧內部有一塊存放控制信息的內存空間,用於記錄通訊操做的控制信息。好比通訊對象的IP地址、端口號、通訊操做的狀態等。因此硬要說套接字是個實體,那就是這些控制信息或者是保存這些控制信息的內存空間。
協議棧執行操做時須要參閱這些控制信息。來決定下一步該作什麼。好比:發送數據時,看看IP地址和端口號;發送數據後,協議棧須要等待對方返回數據的響應信息,可是數據可能會半途丟失。咱們不可能一直等待,因此套接字中須要記錄是否已經收到或者發送數據了多久,才方便知道是否要重發數據。套接字的控制信息還有不少做用,在此不一一列舉了。
協議棧是根據套接字中記錄的控制信息工做的。
建立套接字時,須要調用Socket庫中的socket組件,注意這裏,大寫的是Socket,小寫是庫中的一個程序組件。
應用程序調用socket程序申請建立套接字,而協議棧則根據應用程序的申請執行建立套接字的操做。
在建立過程當中,協議棧會分配一個用於存放套接字所需的內存空間,用於存放記錄套接字操做的控制信息。建立套接字時,數據收發操做還沒開始,因此把這初始狀態的信息存入內存空間中。到此,建立套接字操做完成。
建立套接字,不只要分配空間,並且須要初始化狀態信息。
而後,套接字須要將它的描述符告訴應用程序。描述符至關於車庫號,告訴我車庫號,我才知道哪一個纔是我要的車庫。一樣,描述符是用在應用程序委託協議棧收發數據的時候。套接字包含了通訊對象的信息,好比已經說過的IP地址、端口號,因此應用程序收到套接字的描述符,應用程序再提供給協議棧,協議棧就知道了套接字中所包含的通訊對象信息,就能夠準備鏈接通訊對象了。
由於歷史緣由,其實這裏的「鏈接」就更像是通訊前的準備,叫「準備」其實更適合
調用socket程序申請建立完套接字,而後應用程序會調用Socket庫的另一個程序組件connect,這樣協議棧就會將本地的套接字與服務器的套接字進行鏈接。這裏的鏈接是指通訊雙方交換控制信息,在套接字記錄一些必要信息並準備數據收發的一連串操做。
咱們說的鏈接不是指網線一直插着的鏈接,不是指通訊過程當中將數據轉換成電信號。而是當應用程序委託發送數據時,協議棧經過描述符找到的套接字取得通訊對象的IP地址和端口號等信息。這屬於鏈接操做的目的之一。
說完應用程序,再說下服務器那邊,服務器也會建立套接字,可是服務器的協議棧和客戶端這邊同樣,沒有相似一個描述符的東西就沒辦法知道通訊對象,無法開始通訊。因此得有客戶端先開始請求,告訴服務器必要信息。好比「我要和你請求,個人IP地址是10.10.1.118,端口號是8900」。因此,應用程序向服務器發送請求,也是鏈接操做的目的之一。
鏈接實際上通訊雙方交換控制信息,在套接字中記錄必要信息並準備數據收發的一連串操做。
控制信息,是控制數據收發操做的一些信息。IP地址、端口號就屬於其中的信息。其他的控制信息,咱們後面再介紹。雙方經過通訊規則進行信息交換從而完成數據收發準備。收發操做,須要一塊臨時存放要收發的數據的內存空間,這塊內存空間叫作緩衝區,它是在鏈接操做過程當中分配的。
控制信息能夠分爲兩類。一是客戶端和服務器相互聯絡時交換的控制信息。二是保存在套接字中,用來控制協議棧操做的信息。
第一類:客戶端和服務器交換的控制信息,不只是在鏈接時須要,包括數據收發和斷開鏈接操做在內,整個通訊過程都須要。咱們前面說過,數據會被分紅一個個網絡包發送,而這些信息就是被添加在客戶端與服務器傳遞的網絡包的開頭。在鏈接階段,因爲數據收發尚未開始,網絡包中沒有實際數據,只有控制信息。這些控制信息位於網絡包的開頭,所以成爲頭部。固然,以太網和IP協議也有本身的頭部(包含着控制信息),爲了不不一樣頭部混淆,咱們通常記做TCP頭部,以太網頭部、IP頭部。本文主要講解TCP頭部,其他知識後面再講,讀者有興趣可先自行查閱。
客戶端和服務器在通訊中會將必要的信息存放在頭部並相互確認。你們如今要知道的就是頭部是用來記錄和交換控制信息的。
第二類:套接字中的控制信息。這裏會保存應用程序傳遞來的信息以及從通訊對象接收到的信息,還有收發數據操做的執行狀態等信息也會保存於此,協議棧根據這些信息來執行每一步操做。
通訊操做中使用的控制信息分爲兩類: (1)頭部中的信息 (2)套接字(協議棧的內存空間)中記錄的信息
上面咱們已經介紹了鏈接(準備)操做的含義,接下來看一下具體操做過程。首先是應用程序調用Socket庫中的connect,相似下面👇
connect (<描述符>,<服務器IP地址>,<服務器端口號>,...)
上面的調用提供了服務器的IP地址和端口號,這些信息會傳遞給協議棧中的TCP模塊。TCP模塊就會與該IP地址對應的對象,也就是與服務器的TCP模塊交換控制信息。
seq:(Sequence Number):本報文段數據的第一個字節的序號 ack:(Acknowledgment Number):確認號——指望收到對方下個報文段的第一個數據字節的序號
控制位包含如下幾部分 URG:緊急指針有效位。 SYN:創建鏈接,當須要創建鏈接時,他的值爲1.即SYN=1 ACK:確認鏈接,當ACK=1是纔有效,ACK=0是此控制位無效。 FIN:斷開鏈接,提出斷開鏈接這一方的值爲1. RST:從新創建鏈接,值爲1時表明從新創建鏈接。 PSH:要求接收方將數據儘快將數據段送達應用層
上圖主要介紹了TCP頭部。其中TCP頭部目前要認知的有發送方和接收方的端口號,序號(seq)是發送方告訴接收方本報文段數據的第一個字節的序號,ack號是接收方告訴發送方已收到了全部數據的第幾個字節。其中ack是Acknowledgment Number的縮寫。可能讀者納悶IP地址在哪,IP地址其實在IP頭部纔有。因爲本文重點是介紹TCP,因此下方只給出IP頭部圖,讀者自行閱讀
應用程序與服務器的TCP模塊交換控制信息這一過程包含幾個步驟:首先,客戶端先建立一個包含表示開始數據收發操做的控制信息的頭部(上面所說網絡包中開頭的控制信息),頭部包含不少字段,其中要關注的重點是客戶端和服務器的端口號,也就是說,客戶端的套接字知道了鏈接服務器的哪一個套接字。而後,咱們把頭部中的控制位的SYN設置爲1,你們能夠認爲它表示鏈接。此外,還需設置適當的序號和窗口大小。
鏈接操做的第一步是在TCP模塊處建立表示鏈接控制信息的頭部
經過TCP頭部中的發送方和接收方的端口號能夠找到要鏈接的套接字
當TCP頭部建立好以後,接下來TCP模塊會將信息傳給IP模塊並委託它進行發送。IP模塊執行網絡包發送操做後,網絡包就會經過網絡發送到服務器的IP模塊,再由服務器的IP模塊把接收到的數據傳給服務器自身的TCP模塊,這時,服務器的TCP模塊會根據TCP頭部的信息找到端口號對應的套接字,而後套接字就會寫入相應的信息,並把狀態改爲正在鏈接。
TCP模塊、IP模塊分別屬於網絡原理中OSI模型7層結構的傳輸層、網絡層,而傳輸層處於網絡層的上一層,也就是高一層,要完成傳送數據,必須從通訊一方的高層傳到低層,再經過網絡傳給通訊另一方的低層,再到那一方的高層完成接收。因此發送數據得從高一層的TCP到低層的IP模塊逐一傳遞。
上述操做完成後,服務器的TCP模塊會返回響應,這個過程跟客戶端發送數據給服務端同樣,須要在TCP頭部中設置發送方和接收方端口以及SYN比特。另外,客戶端向服務器發送第一個網絡包時,因爲服務器尚未接受過網絡包,因此ACK比特設爲0,那麼在返回響應就須要將ACK控制位設爲1,表示已經收到相應的網絡包。網絡中常常發生錯誤,網絡包也會丟失。所以通訊雙方必須相互確認網絡包是否已經送達,通訊雙方如何確認?其實就是經過設置ACK。接下來,服務器TCP模塊會講TCP頭部傳給IP模塊,並委託IP模塊向客戶端返回響應。
而後,網絡包就會返回客戶端,經過IP模塊到達TCP模塊,並經過TCP頭部信息確認鏈接服務器的操做是否成功。若是SYN爲1,則表示鏈接成功,這時會向套接字中寫入服務器的IP地址、端口號等信息,同時還會將狀態改爲鏈接完畢。到這裏,客戶端的操做就已經完成。但其實還剩下一個步驟,客戶端收到數據後,也要像服務器那樣把把ACK設置爲1,併發回給服務器,告訴服務器,我已經收到服務器發來的響應包,當服務器收到這個返回包後,鏈接操做纔算所有完成。
有沒有以爲上面的雙方相互確認網絡包操做,彷佛很熟悉,沒錯!它其實就是tcp的三次握手。
TCP三次握手 1.A向B發起創建鏈接請求: 2.B收到A的發送信號,而且向A發送確認信息 3.A收到B的確認信號,而且向B發送確認信號
鏈接(準備)操做完成後,套接字能夠隨時進行收發數據了,這個時候咱們能夠理解通訊雙方已經有一條相連的管道,這條管道鏈接着雙方的套接字。固然這條管道並不真正存在,只是業界爲了方便理解,比喻而已。
創建鏈接後,協議棧的鏈接操做就結束了。也就是說,當初應用程序調用Socket庫中connect程序組件操做已經執行完畢,控制流程又從新交回到客戶端。等到後面的收發數據操做。
在此,收發數據的建立套接字階段、鏈接階段已經講完,剩下的通訊階段、斷開階段留到下次再講。網絡的東西很枯燥,而且並非那麼可視化,學會的要訣是沉住氣,看到這裏,若是你如今還不能講到收發數據的前兩個步驟,請回到文章頂部,再看一遍。Over and over again,你就會學有所成。
歡迎關注技術公衆號「程序員大咖秀」