linux伺服器開發三(網路編程)

来源:http://www.cnblogs.com/zfc2201/archive/2017/01/21/6336623.html
-Advertisement-
Play Games

網路基礎 協議的概念 什麼是協議 從應用的角度出發,協議可理解為“規則”,是數據傳輸和數據的解釋的規則。 假設,A、B雙方欲傳輸文件。規定: 第一次,傳輸文件名,接收方接收到文件名,應答OK給傳輸方; 第二次,發送文件的尺寸,接收方接收到該數據再次應答一個OK; 第三次,傳輸文件內容。同樣,接收方接 ...


網路基礎

協議的概念

什麼是協議

  • 從應用的角度出發,協議可理解為“規則”,是數據傳輸和數據的解釋的規則。
  • 假設,A、B雙方欲傳輸文件。規定:
  • 第一次,傳輸文件名,接收方接收到文件名,應答OK給傳輸方;
  • 第二次,發送文件的尺寸,接收方接收到該數據再次應答一個OK;
  • 第三次,傳輸文件內容。同樣,接收方接收數據完成後應答OK表示文件內容接收成功。
  • 由此,無論A、B之間傳遞何種文件,都是通過三次數據傳輸來完成。A、B之間形成了一個最簡單的數據傳輸規則。雙方都按此規則發送、接收數據。A、B之間達成的這個相互遵守的規則即為協議。
  • 這種僅在A、B之間被遵守的協議稱之為原始協議。當此協議被更多的人採用,不斷的增加、改進、維護、完善。最終形成一個穩定的、完整的文件傳輸協議,被廣泛應用於各種文件傳輸過程中。該協議就成為一個標準協議。最早的ftp協議就是由此衍生而來。
  • TCP協議註重數據的傳輸。http協議著重於數據的解釋。

典型協議

  • 傳輸層 常見協議有TCP/UDP協議。
  • 應用層 常見的協議有HTTP協議,FTP協議。
  • 網路層 常見協議有IP協議、ICMP協議、IGMP協議。
  • 網路介面層 常見協議有ARP協議、RARP協議。
  • TCP傳輸控制協議(Transmission Control Protocol)是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議。
  • UDP用戶數據報協議(User Datagram Protocol)是OSI參考模型中一種無連接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務。
  • HTTP超文本傳輸協議(Hyper Text Transfer Protocol)是互聯網上應用最為廣泛的一種網路協議。
  • FTP文件傳輸協議(File Transfer Protocol)
  • IP協議是網際網路互聯協議(Internet Protocol)
  • ICMP協議是Internet控制報文協議(Internet Control Message Protocol)它是TCP/IP協議族的一個子協議,用於在IP主機、路由器之間傳遞控制消息。
  • IGMP協議是 Internet 組管理協議(Internet Group Management Protocol),是網際網路協議家族中的一個組播協議。該協議運行在主機和組播路由器之間。
  • ARP協議是正向地址解析協議(Address Resolution Protocol),通過已知的IP,尋找對應主機的MAC地址。
  • RARP協議是反向地址轉換協議,通過MAC地址確定IP地址。

網路應用程式設計模式

C/S模式

  • 傳統的網路應用設計模式,客戶機(client)/伺服器(server)模式。需要在通訊兩端各自部署客戶機和伺服器來完成數據通信。

B/S模式

  • 瀏覽器(Browser)/伺服器(server)模式。只需在一端部署伺服器,而另外一端使用每台PC都預設配置的瀏覽器即可完成數據的傳輸。

優缺點

  • 對於C/S模式來說,其優點明顯。客戶端位於目標主機上可以保證性能,將數據緩存至客戶端本地,從而提高數據傳輸效率。且,一般來說客戶端和伺服器程式由一個開發團隊創作,所以他們之間所採用的協議相對靈活。可以在標準協議的基礎上根據需求裁剪及定製。例如,騰訊公司所採用的通信協議,即為ftp協議的修改剪裁版。
  • 因此,傳統的網路應用程式及較大型的網路應用程式都首選C/S模式進行開發。如,知名的網路游戲魔獸世界。3D畫面,數據量龐大,使用C/S模式可以提前在本地進行大量數據的緩存處理,從而提高觀感。
  • C/S模式的缺點也較突出。由於客戶端和伺服器都需要有一個開發團隊來完成開發。工作量將成倍提升,開發周期較長。另外,從用戶角度出發,需要將客戶端安插至用戶主機上,對用戶主機的安全性構成威脅。這也是很多用戶不願使用C/S模式應用程式的重要原因。
  • B/S模式相比C/S模式而言,由於它沒有獨立的客戶端,使用標準瀏覽器作為客戶端,其工作開發量較小。只需開發伺服器端即可。另外由於其採用瀏覽器顯示數據,因此移植性非常好,不受平臺限制。如早期的偷菜游戲,在各個平臺上都可以完美運行。
  • B/S模式的缺點也較明顯。由於使用第三方瀏覽器,因此網路應用支持受限。另外,沒有客戶端放到對方主機上,緩存數據不盡如人意,從而傳輸數據量受到限制。應用的觀感大打折扣。第三,必須與瀏覽器一樣,採用標準http協議進行通信,協議選擇不靈活
  • 因此在開發過程中,模式的選擇由上述各自的特點決定。根據實際需求選擇應用程式設計模式。

分層模型

OSI七層模型

OSI模型

  • 1.物理層:主要定義物理設備標準,如網線的介面類型、光纖的介面類型、各種傳輸介質的傳輸速率等。它的主要作用是傳輸比特流(就是由1、0轉化為電流強弱來進行傳輸,到達目的地後再轉化為1、0,也就是我們常說的數模轉換與模數轉換)。這一層的數據叫做比特。
  • 2.數據鏈路層:定義瞭如何讓格式化數據以幀為單位進行傳輸,以及如何讓控制對物理介質的訪問。這一層通常還提供錯誤檢測和糾正,以確保數據的可靠傳輸。如:串口通信中使用到的115200、8、N、1
  • 3.網路層:在位於不同地理位置的網路中的兩個主機系統之間提供連接和路徑選擇。Internet的發展使得從世界各站點訪問信息的用戶數大大增加,而網路層正是管理這種連接的層。
  • 4.傳輸層:定義了一些傳輸數據的協議和埠號(WWW埠80等),如:TCP(傳輸控制協議,傳輸效率低,可靠性強,用於傳輸可靠性要求高,數據量大的數據),UDP(用戶數據報協議,與TCP特性恰恰相反,用於傳輸可靠性要求不高,數據量小的數據,如QQ聊天數據就是通過這種方式傳輸的)。 主要是將從下層接收的數據進行分段和傳輸,到達目的地址後再進行重組。常常把這一層數據叫做段。
  • 5.會話層:通過傳輸層(埠號:傳輸埠與接收埠)建立數據傳輸的通路。主要在你的系統之間發起會話或者接受會話請求(設備之間需要互相認識可以是IP也可以是MAC或者是主機名)。
  • 6.表示層:可確保一個系統的應用層所發送的信息可以被另一個系統的應用層讀取。例如,PC程式與另一臺電腦進行通信,其中一臺電腦使用擴展二一十進位交換碼(EBCDIC),而另一臺則使用美國信息交換標準碼(ASCII)來表示相同的字元。如有必要,表示層會通過使用一種通格式來實現多種數據格式之間的轉換。
  • 7.應用層:是最靠近用戶的OSI層。這一層為用戶的應用程式(例如電子郵件、文件傳輸和終端模擬)提供網路服務。

TCP/IP四層模型

  • TCP/IP網路協議棧分為應用層(Application)、傳輸層(Transport)、網路層(Network)和鏈路層(Link)四層。如下圖所示:

TCP/IP模型

  • 一般在應用開發過程中,討論最多的是TCP/IP模型。

通信過程

  • 兩台電腦通過TCP/IP協議通訊的過程如下所示:

TCP/IP通信過程

  • 上圖對應兩台電腦在同一網段中的情況,如果兩台電腦在不同的網段中,那麼數據從一臺電腦到另一臺電腦傳輸過程中要經過一個或多個路由器,如下圖所示:

跨路由通信

  • 鏈路層有乙太網、令牌環網等標準,鏈路層負責網卡設備的驅動、幀同步(即從網線上檢測到什麼信號算作新幀的開始)、衝突檢測(如果檢測到衝突就自動重發)、數據差錯校驗等工作。交換機是工作在鏈路層的網路設備,可以在不同的鏈路層網路之間轉發數據幀(比如十兆乙太網和百兆乙太網之間、乙太網和令牌環網之間),由於不同鏈路層的幀格式不同,交換機要將進來的數據包拆掉鏈路層首部重新封裝之後再轉發。
  • 網路層的IP協議是構成Internet的基礎。Internet上的主機通過IP地址來標識,Inter-net上有大量路由器負責根據IP地址選擇合適的路徑轉發數據包,數據包從Internet上的源主機到目的主機往往要經過十多個路由器。路由器是工作在第三層的網路設備,同時兼有交換機的功能,可以在不同的鏈路層介面之間轉發數據包,因此路由器需要將進來的數據包拆掉網路層和鏈路層兩層首部並重新封裝。IP協議不保證傳輸的可靠性,數據包在傳輸過程中可能丟失,可靠性可以在上層協議或應用程式中提供支持。
  • 網路層負責點到點(ptop,point-to-point)的傳輸(這裡的“點”指主機或路由器),而傳輸層負責端到端(etoe,end-to-end)的傳輸(這裡的“端”指源主機和目的主機)。傳輸層可選擇TCP或UDP協議。
  • TCP是一種面向連接的、可靠的協議,有點像打電話,雙方拿起電話互通身份之後就建立了連接,然後說話就行了,這邊說的話那邊保證聽得到,並且是按說話的順序聽到的,說完話掛機斷開連接。也就是說TCP傳輸的雙方需要首先建立連接,之後由TCP協議保證數據收發的可靠性,丟失的數據包自動重發,上層應用程式收到的總是可靠的數據流,通訊之後關閉連接。
  • UDP是無連接的傳輸協議,不保證可靠性,有點像寄信,信寫好放到郵筒里,既不能保證信件在郵遞過程中不會丟失,也不能保證信件寄送順序。使用UDP協議的應用程式需要自己完成丟包重發、消息排序等工作。
  • 目的主機收到數據包後,如何經過各層協議棧最後到達應用程式呢?其過程如下圖所示:

數據包網路傳輸過程

  • 乙太網驅動程式首先根據乙太網首部中的“上層協議”欄位確定該數據幀的有效載荷(payload,指除去協議首部之外實際傳輸的數據)是IP、ARP還是RARP協議的數據報,然後交給相應的協議處理。假如是IP數據報,IP協議再根據IP首部中的“上層協議”欄位確定該數據報的有效載荷是TCP、UDP、ICMP還是IGMP,然後交給相應的協議處理。假如是TCP段或UDP段,TCP或UDP協議再根據TCP首部或UDP首部的“埠號”欄位確定應該將應用層數據交給哪個用戶進程。IP地址是標識網路中不同主機的地址,而埠號就是同一臺主機上標識不同進程的地址,IP地址和埠號合起來標識網路中唯一的進程。
  • 雖然IP、ARP和RARP數據報都需要乙太網驅動程式來封裝成幀,但是從功能上劃分,ARP和RARP屬於鏈路層,IP屬於網路層。雖然ICMP、IGMP、TCP、UDP的數據都需要IP協議來封裝成數據報,但是從功能上劃分,ICMP、IGMP與IP同屬於網路層,TCP和UDP屬於傳輸層。

協議格式

數據包封裝

  • 傳輸層及其以下的機制由內核提供,應用層由用戶進程提供(後面將介紹如何使用socket API編寫應用程式),應用程式對通訊數據的含義進行解釋,而傳輸層及其以下處理通訊的細節,將數據從一臺電腦通過一定的路徑發送到另一臺電腦。應用層數據通過協議棧發到網路上時,每層協議都要加上一個數據首部(header),稱為封裝(Encapsulation),如下圖所示:

TCP/IP數據包封裝

  • 不同的協議層對數據包有不同的稱謂,在傳輸層叫做段(segment),在網路層叫做數據報(datagram),在鏈路層叫做幀(frame)。數據封裝成幀後發到傳輸介質上,到達目的主機後每層協議再剝掉相應的首部,最後將應用層數據交給應用程式處理。

乙太網幀格式

  • 乙太網的幀格式如下所示:

乙太網幀格式

  • 其中的源地址和目的地址是指網卡的硬體地址(也叫MAC地址),長度是48位,是在網卡出廠時固化的。可在shell中使用ifconfig命令查看,“HWaddr 00:15:F2:14:9E:3F”部分就是硬體地址。協議欄位有三種值,分別對應IP、ARP、RARP。幀尾是CRC校驗碼。
  • 乙太網幀中的數據長度規定最小46位元組,最大1500位元組,ARP和RARP數據包的長度不夠46位元組,要在後面補填充位。最大值1500稱為乙太網的最大傳輸單元(MTU),不同的網路類型有不同的MTU,如果一個數據包從乙太網路由到撥號鏈路上,數據包長度大於撥號鏈路的MTU,則需要對數據包進行分片(fragmentation)。ifconfig命令輸出中也有“MTU:1500”。註意,MTU這個概念指數據幀中有效載荷的最大長度,不包括幀頭長度。

ARP數據報格式

  • 在網路通訊時,源主機的應用程式知道目的主機的IP地址和埠號,卻不知道目的主機的硬體地址,而數據包首先是被網卡接收到再去處理上層協議的,如果接收到的數據包的硬體地址與本機不符,則直接丟棄。因此在通訊前必須獲得目的主機的硬體地址。ARP協議就起到這個作用。源主機發出ARP請求,詢問“IP地址是192.168.0.1的主機的硬體地址是多少”,並將這個請求廣播到本地網段(乙太網幀首部的硬體地址填FF:FF:FF:FF:FF:FF表示廣播),目的主機接收到廣播的ARP請求,發現其中的IP地址與本機相符,則發送一個ARP應答數據包給源主機,將自己的硬體地址填寫在應答包中。

  • 每台主機都維護一個ARP緩存表,可以用arp -a命令查看。緩存表中的表項有過期時間(一般為20分鐘),如果20分鐘內沒有再次使用某個表項,則該表項失效,下次還要發ARP請求來獲得目的主機的硬體地址。想一想,為什麼表項要有過期時間而不是一直有效?

  • ARP數據報的格式如下所示:

ARP數據報格式

  • 源MAC地址、目的MAC地址在乙太網首部和ARP請求中各出現一次,對於鏈路層為乙太網的情況是多餘的,但如果鏈路層是其它類型的網路則有可能是必要的。硬體類型指鏈路層網路類型,1為乙太網,協議類型指要轉換的地址類型,0x0800為IP地址,後面兩個地址長度對於乙太網地址和IP地址分別為6和4(位元組),op欄位為1表示ARP請求,op欄位為2表示ARP應答。

  • 看一個具體的例子。

  • 請求幀如下(為了清晰在每行的前面加了位元組計數,每行16個位元組):

    乙太網首部(14位元組)
    0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06
    ARP幀(28位元組)
    0000: 00 01
    0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37
    0020: 00 00 00 00 00 00 c0 a8 00 02
    填充位(18位元組)
    0020: 00 77 31 d2 50 10
    0030: fd 78 41 d3 00 00 00 00 00 00 00 00
    
  • 乙太網首部:目的主機採用廣播地址,源主機的MAC地址是00:05:5d:61:58:a8,上層協議類型0x0806表示ARP。

  • ARP幀:硬體類型0x0001表示乙太網,協議類型0x0800表示IP協議,硬體地址(MAC地址)長度為6,協議地址(IP地址)長度為4,op為0x0001表示請求目的主機的MAC地址,源主機MAC地址為00:05:5d:61:58:a8,源主機IP地址為c0 a8 00 37(192.168.0.55),目的主機MAC地址全0待填寫,目的主機IP地址為c0 a8 00 02(192.168.0.2)。

  • 由於乙太網規定最小數據長度為46位元組,ARP幀長度只有28位元組,因此有18位元組填充位,填充位的內容沒有定義,與具體實現相關。

  • 應答幀如下:

    乙太網首部
    0000: 00 05 5d 61 58 a8 00 05 5d a1 b8 40 08 06
    ARP幀
    0000: 00 01
    0010: 08 00 06 04 00 02 00 05 5d a1 b8 40 c0 a8 00 02
    0020: 00 05 5d 61 58 a8 c0 a8 00 37
    填充位
    0020: 00 77 31 d2 50 10
    0030: fd 78 41 d3 00 00 00 00 00 00 00 00
    
  • 乙太網首部:目的主機的MAC地址是00:05:5d:61:58:a8,源主機的MAC地址是00:05:5d:a1:b8:40,上層協議類型0x0806表示ARP。

  • ARP幀:硬體類型0x0001表示乙太網,協議類型0x0800表示IP協議,硬體地址(MAC地址)長度為6,協議地址(IP地址)長度為4,op為0x0002表示應答,源主機MAC地址為00:05:5d:a1:b8:40,源主機IP地址為c0 a8 00 02(192.168.0.2),目的主機MAC地址為00:05:5d:61:58:a8,目的主機IP地址為c0 a8 00 37(192.168.0.55)。

  • 思考題:如果源主機和目的主機不在同一網段,ARP請求的廣播幀無法穿過路由器,源主機如何與目的主機通信?

IP段格式

IP數據報格式

  • IP數據報的首部長度和數據長度都是可變長的,但總是4位元組的整數倍。對於IPv4,4位版本欄位是4。4位首部長度的數值是以4位元組為單位的,最小值為5,也就是說首部長度最小是4x5=20位元組,也就是不帶任何選項的IP首部,4位能表示的最大值是15,也就是說首部長度最大是60位元組。8位TOS欄位有3個位用來指定IP數據報的優先順序(目前已經廢棄不用),還有4個位表示可選的服務類型(最小延遲、最大?吐量、最大可靠性、最小成本),還有一個位總是0。總長度是整個數據報(包括IP首部和IP層payload)的位元組數。每傳一個IP數據報,16位的標識加1,可用於分片和重新組裝數據報。3位標誌和13位片偏移用於分片。TTL(Time to live)是這樣用的:源主機為數據包設定一個生存時間,比如64,每過一個路由器就把該值減1,如果減到0就表示路由已經太長了仍然找不到目的主機的網路,就丟棄該包,因此這個生存時間的單位不是秒,而是跳(hop)。協議欄位指示上層協議是TCP、UDP、ICMP還是IGMP。然後是校驗和,只校驗IP首部,數據的校驗由更高層協議負責。IPv4的IP地址長度為32位。

  • 想一想,前面講了乙太網幀中的最小數據長度為46位元組,不足46位元組的要用填充位元組補上,那麼如何界定這46位元組里前多少個位元組是IP、ARP或RARP數據報而後面是填充位元組?

UDP數據報格式

UDP數據段

  • 下麵分析一幀基於UDP的TFTP協議幀。

    乙太網首部
    0000: 00 05 5d 67 d0 b1 00 05 5d 61 58 a8 08 00
    IP首部
    0000: 45 00
    0010: 00 53 93 25 00 00 80 11 25 ec c0 a8 00 37 c0 a8
    0020: 00 01
    UDP首部
    0020: 05 d4 00 45 00 3f ac 40
    TFTP協議
    0020: 00 01 'c'':''\''q'
    0030: 'w''e''r''q''.''q''w''e'00 'n''e''t''a''s''c''i'
    0040: 'i'00 'b''l''k''s''i''z''e'00 '5''1''2'00 't''i'
    0050: 'm''e''o''u''t'00 '1''0'00 't''s''i''z''e'00 '0'
    0060: 00乙太網首部:源MAC地址是00:05:5d:61:58:a8,目的MAC地址是00:05:5d:67:d0:b1,上層協議類型0x0800表示IP。
    
  • IP首部:每一個位元組0x45包含4位版本號和4位首部長度,版本號為4,即IPv4,首部長度為5,說明IP首部不帶有選項欄位。服務類型為0,沒有使用服務。16位總長度欄位(包括IP首部和IP層payload的長度)為0x0053,即83位元組,加上乙太網首部14位元組可知整個幀長度是97位元組。IP報標識是0x9325,標誌欄位和片偏移欄位設置為0x0000,就是DF=0允許分片,MF=0此數據報沒有更多分片,沒有分片偏移。TTL是0x80,也就是128。上層協議0x11表示UDP協議。IP首部校驗和為0x25ec,源主機IP是c0 a8 00 37(192.168.0.55),目的主機IP是c0 a8 00 01(192.168.0.1)。

  • UDP首部:源埠號0x05d4(1492)是客戶端的埠號,目的埠號0x0045(69)是TFTP服務的well-known埠號。UDP報長度為0x003f,即63位元組,包括UDP首部和UDP層pay-load的長度。UDP首部和UDP層payload的校驗和為0xac40。

  • TFTP是基於文本的協議,各欄位之間用位元組0分隔,開頭的00 01表示請求讀取一個文件,接下來的各欄位是:

    c:\qwerq.qwe
    netascii
    blksize 512
    timeout 10
    tsize 0
    
  • 一般的網路通信都是像TFTP協議這樣,通信的雙方分別是客戶端和伺服器,客戶端主動發起請求(上面的例子就是客戶端發起的請求幀),而伺服器被動地等待、接收和應答請求。客戶端的IP地址和埠號唯一標識了該主機上的TFTP客戶端進程,伺服器的IP地址和埠號唯一標識了該主機上的TFTP服務進程,由於客戶端是主動發起請求的一方,它必須知道伺服器的IP地址和TFTP服務進程的埠號,所以,一些常見的網路協議有預設的伺服器埠,例如HTTP服務預設TCP協議的80埠,FTP服務預設TCP協議的21埠,TFTP服務預設UDP協議的69埠(如上例所示)。在使用客戶端程式時,必須指定伺服器的主機名或IP地址,如果不明確指定埠號則採用預設埠,請讀者查閱ftp、tftp等程式的man page瞭解如何指定埠號。/etc/services中列出了所有well-known的服務埠和對應的傳輸層協議,這是由IANA(Internet Assigned Numbers Authority)規定的,其中有些服務既可以用TCP也可以用UDP,為了清晰,IANA規定這樣的服務採用相同的TCP或UDP預設埠號,而另外一些TCP和UDP的相同埠號卻對應不同的服務。

  • 很多服務有well-known的埠號,然而客戶端程式的埠號卻不必是well-known的,往往是每次運行客戶端程式時由系統自動分配一個空閑的埠號,用完就釋放掉,稱為ephemeral的埠號,想想這是為什麼?

  • 前面提過,UDP協議不面向連接,也不保證傳輸的可靠性,例如:

  • 發送端的UDP協議層只管把應用層傳來的數據封裝成段交給IP協議層就算完成任務了,如果因為網路故障該段無法發到對方,UDP協議層也不會給應用層返回任何錯誤信息。

  • 接收端的UDP協議層只管把收到的數據根據埠號交給相應的應用程式就算完成任務了,如果發送端發來多個數據包並且在網路上經過不同的路由,到達接收端時順序已經錯亂了,UDP協議層也不保證按發送時的順序交給應用層。

  • 通常接收端的UDP協議層將收到的數據放在一個固定大小的緩衝區中等待應用程式來提取和處理,如果應用程式提取和處理的速度很慢,而發送端發送的速度很快,就會丟失數據包,UDP協議層並不報告這種錯誤。

  • 因此,使用UDP協議的應用程式必須考慮到這些可能的問題並實現適當的解決方案,例如等待應答、超時重發、為數據包編號、流量控制等。一般使用UDP協議的應用程式實現都比較簡單,只是發送一些對可靠性要求不高的消息,而不發送大量的數據。例如,基於UDP的TFTP協議一般只用於傳送小文件(所以才叫trivial的ftp),而基於TCP的FTP協議適用於 各種文件的傳輸。TCP協議又是如何用面向連接的服務來代替應用程式解決傳輸的可靠性問題呢。

TCP數據報格式

TCP數據段

  • 與UDP協議一樣也有源埠號和目的埠號,通訊的雙方由IP地址和埠號標識。32位序號、32位確認序號、視窗大小稍後詳細解釋。4位首部長度和IP協議頭類似,表示TCP協議頭的長度,以4位元組為單位,因此TCP協議頭最長可以是4x15=60位元組,如果沒有選項欄位,TCP協議頭最短20位元組。URG、ACK、PSH、RST、SYN、FIN是六個控制位,本節稍後將解釋SYN、ACK、FIN、RST四個位,其它位的解釋從略。16位檢驗和將TCP協議頭和數據都計算在內。緊急指針和各種選項的解釋從略。

TCP協議

TCP通信時序

  • 下圖是一次TCP通訊的時序圖。TCP連接建立斷開。包含大家熟知的三次握手和四次握手。

TCP通訊時序

  • 在這個例子中,首先客戶端主動發起連接、發送請求,然後伺服器端響應請求,然後客戶端主動關閉連接。兩條豎線表示通訊的兩端,從上到下表示時間的先後順序,註意,數據從一端傳到網路的另一端也需要時間,所以圖中的箭頭都是斜的。雙方發送的段按時間順序編號為1-10,各段中的主要信息在箭頭上標出,例如段2的箭頭上標著SYN, 8000(0), ACK1001, ,表示該段中的SYN位置1,32位序號是8000,該段不攜帶有效載荷(數據位元組數為0),ACK位置1,32位確認序號是1001,帶有一個mss(Maximum Segment Size,最大報文長度)選項值為1024。

  • 建立連接(三次握手)的過程:

    • 1、客戶端發送一個帶SYN標誌的TCP報文到伺服器。這是三次握手過程中的段1。 客戶端發出段1,SYN位表示連接請求。序號是1000,這個序號在網路通訊中用作臨時的地址,每發一個數據位元組,這個序號要加1,這樣在接收端可以根據序號排出數據包的正確順序,也可以發現丟包的情況,另外,規定SYN位和FIN位也要占一個序號,這次雖然沒發數據,但是由於發了SYN位,因此下次再發送應該用序號1001。mss表示最大段尺寸,如果一個段太大,封裝成幀後超過了鏈路層的最大幀長度,就必須在IP層分片,為了避免這種情況,客戶端聲明自己的最大段尺寸,建議伺服器端發來的段不要超過這個長度。

    • 2、伺服器端回應客戶端,是三次握手中的第2個報文段,同時帶ACK標誌和SYN標誌。它表示對剛纔客戶端SYN的回應;同時又發送SYN給客戶端,詢問客戶端是否準備好進行數據通訊。 伺服器發出段2,也帶有SYN位,同時置ACK位表示確認,確認序號是1001,表示“我接收到序號1000及其以前所有的段,請你下次發送序號為1001的段”,也就是應答了客戶端的連接請求,同時也給客戶端發出一個連接請求,同時聲明最大尺寸為1024。

    • 3、客戶必須再次回應伺服器端一個ACK報文,這是報文段3。 客戶端發出段3,對伺服器的連接請求進行應答,確認序號是8001。在這個過程中,客戶端和伺服器分別給對方發了連接請求,也應答了對方的連接請求,其中伺服器的請求和應答在一個段中發出,因此一共有三個段用於建立連接,稱為“三方握手(three-way-handshake)”。在建立連接的同時,雙方協商了一些信息,例如雙方發送序號的初始值、最大段尺寸等。

    • 在TCP通訊中,如果一方收到另一方發來的段,讀出其中的目的埠號,發現本機並沒有任何進程使用這個埠,就會應答一個包含RST位的段給另一方。例如,伺服器並沒有任何進程使用8080埠,我們卻用telnet客戶端去連接它,伺服器收到客戶端發來的SYN段就會應答一個RST段,客戶端的telnet程式收到RST段後報告錯誤Connection refused:

      $ telnet 192.168.0.200 8080
      Trying 192.168.0.200...
      telnet: Unable to connect to remote host: Connection refused
      
  • 數據傳輸的過程:

    • 1、客戶端發出段4,包含從序號1001開始的20個位元組數據。
    • 2、伺服器發出段5,確認序號為1021,對序號為1001-1020的數據表示確認收到,同時請求發送序號1021開始的數據,伺服器在應答的同時也向客戶端發送從序號8001開始的10個位元組數據,這稱為piggyback。
    • 3、客戶端發出段6,對伺服器發來的序號為8001-8010的數據表示確認收到,請求發送序號8011開始的數據。
    • 在數據傳輸過程中,ACK和確認序號是非常重要的,應用程式交給TCP協議發送的數據會暫存在TCP層的發送緩衝區中,發出數據包給對方之後,只有收到對方應答的ACK段才知道該數據包確實發到了對方,可以從發送緩衝區中釋放掉了,如果因為網路故障丟失了數據包或者丟失了對方發回的ACK段,經過等待超時後TCP協議自動將發送緩衝區中的數據包重發。
  • 關閉連接(四次握手)的過程:

    • 由於TCP連接是全雙工的,因此每個方向都必須單獨進行關閉。這原則是當一方完成它的數據發送任務後就能發送一個FIN來終止這個方向的連接。收到一個 FIN只意味著這一方向上沒有數據流動,一個TCP連接在收到一個FIN後仍能發送數據。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
    • 1、客戶端發出段7,FIN位表示關閉連接的請求。
    • 2、伺服器發出段8,應答客戶端的關閉連接請求。
    • 3、伺服器發出段9,其中也包含FIN位,向客戶端發送關閉連接請求。
    • 4、客戶端發出段10,應答伺服器的關閉連接請求。
    • 建立連接的過程是三方握手,而關閉連接通常需要4個段,伺服器的應答和關閉連接請求通常不合併在一個段中,因為有連接半關閉的情況,這種情況下客戶端關閉連接之後就不能再發送數據給伺服器了,但是伺服器還可以發送數據給客戶端,直到伺服器也關閉連接為止。

滑動視窗 (TCP流量控制)

  • 介紹UDP時我們描述了這樣的問題:如果發送端發送的速度較快,接收端接收到數據後處理的速度較慢,而接收緩衝區的大小是固定的,就會丟失數據。TCP協議通過“滑動視窗(Sliding Window)”機制解決這一問題。看下圖的通訊過程:

滑動視窗

  • 1、發送端發起連接,聲明最大段尺寸是1460,初始序號是0,視窗大小是4K,表示“我的接收緩衝區還有4K位元組空閑,你發的數據不要超過4K”。接收端應答連接請求,聲明最大段尺寸是1024,初始序號是8000,視窗大小是6K。發送端應答,三方握手結束。
  • 2、發送端發出段4-9,每個段帶1K的數據,發送端根據視窗大小知道接收端的緩衝區滿了,因此停止發送數據。
  • 3、接收端的應用程式提走2K數據,接收緩衝區又有了2K空閑,接收端發出段10,在應答已收到6K數據的同時聲明視窗大小為2K。
  • 4、接收端的應用程式又提走2K數據,接收緩衝區有4K空閑,接收端發出段11,重新聲明視窗大小為4K。
  • 5、發送端發出段12-13,每個段帶2K數據,段13同時還包含FIN位。
  • 6、接收端應答接收到的2K數據(6145-8192),再加上FIN位占一個序號8193,因此應答序號是8194,連接處於半關閉狀態,接收端同時聲明視窗大小為2K。
  • 7、接收端的應用程式提走2K數據,接收端重新聲明視窗大小為4K。
  • 8、接收端的應用程式提走剩下的2K數據,接收緩衝區全空,接收端重新聲明視窗大小為6K。
  • 9、接收端的應用程式在提走全部數據後,決定關閉連接,發出段17包含FIN位,發送端應答,連接完全關閉。

  • 上圖在接收端用小方塊表示1K數據,實心的小方塊表示已接收到的數據,虛線框表示接收緩衝區,因此套在虛線框中的空心小方塊表示視窗大小,從圖中可以看出,隨著應用程式提走數據,虛線框是向右滑動的,因此稱為滑動視窗。

  • 從這個例子還可以看出,發送端是一K一K地發送數據,而接收端的應用程式可以兩K兩K地提走數據,當然也有可能一次提走3K或6K數據,或者一次只提走幾個位元組的數據。也就是說,應用程式所看到的數據是一個整體,或說是一個流(stream),在底層通訊中這些數據可能被拆成很多數據包來發送,但是一個數據包有多少位元組對應用程式是不可見的,因此TCP協議是面向流的協議。而UDP是面向消息的協議,每個UDP段都是一條消息,應用程式必須以消息為單位提取數據,不能一次提取任意位元組的數據,這一點和TCP是很不同的。

TCP狀態轉換

  • 這個圖N多人都知道,它排除和定位網路或系統故障時大有幫助,但是怎樣牢牢地將這張圖刻在腦中呢?那麼你就一定要對這張圖的每一個狀態,及轉換的過程有深刻的認識,不能只停留在一知半解之中。下麵對這張圖的11種狀態詳細解析一下,以便加強記憶!不過在這之前,先回顧一下TCP建立連接的三次握手過程,以及 關閉連接的四次握手過程。

TCP狀態轉換圖

  • CLOSED:表示初始狀態。

  • LISTEN:該狀態表示伺服器端的某個SOCKET處於監聽狀態,可以接受連接。

  • SYN_SENT:這個狀態與SYN_RCVD遙相呼應,當客戶端SOCKET執行CONNECT連接時,它首先發送SYN報文,隨即進入到了SYN_SENT狀態,並等待服務端的發送三次握手中的第2個報文。SYN_SENT狀態表示客戶端已發送SYN報文。

  • SYN_RCVD: 該狀態表示接收到SYN報文,在正常情況下,這個狀態是伺服器端的SOCKET在建立TCP連接時的三次握手會話過程中的一個中間狀態,很短暫。此種狀態時,當收到客戶端的ACK報文後,會進入到ESTABLISHED狀態。

  • ESTABLISHED:表示連接已經建立。

  • FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2狀態的真正含義都是表示等待對方的FIN報文。區別是:

    • FIN_WAIT_1狀態是當socket在ESTABLISHED狀態時,想主動關閉連接,向對方發送了FIN報文,此時該socket進入到FIN_WAIT_1狀態。
    • FIN_WAIT_2狀態是當對方回應ACK後,該socket進入到FIN_WAIT_2狀態,正常情況下,對方應馬上回應ACK報文,所以FIN_WAIT_1狀態一般較難見到,而FIN_WAIT_2狀態可用netstat看到。
  • FIN_WAIT_2:主動關閉鏈接的一方,發出FIN收到ACK以後進入該狀態。稱之為半連接或半關閉狀態。該狀態下的socket只能接收數據,不能發。

  • TIME_WAIT: 表示收到了對方的FIN報文,併發送出了ACK報文,等2MSL後即可回到CLOSED可用狀態。如果FIN_WAIT_1狀態下,收到對方同時帶 FIN標誌和ACK標誌的報文時,可以直接進入到TIME_WAIT狀態,而無須經過FIN_WAIT_2狀態。

  • CLOSING: 這種狀態較特殊,屬於一種較罕見的狀態。正常情況下,當你發送FIN報文後,按理來說是應該先收到(或同時收到)對方的 ACK報文,再收到對方的FIN報文。但是CLOSING狀態表示你發送FIN報文後,並沒有收到對方的ACK報文,反而卻也收到了對方的FIN報文。什麼情況下會出現此種情況呢?如果雙方幾乎在同時close一個SOCKET的話,那麼就出現了雙方同時發送FIN報文的情況,也即會出現CLOSING狀態,表示雙方都正在關閉SOCKET連接。

  • CLOSE_WAIT: 此種狀態表示在等待關閉。當對方關閉一個SOCKET後發送FIN報文給自己,系統會回應一個ACK報文給對方,此時則進入到CLOSE_WAIT狀態。接下來呢,察看是否還有數據發送給對方,如果沒有可以 close這個SOCKET,發送FIN報文給對方,即關閉連接。所以在CLOSE_WAIT狀態下,需要關閉連接。

  • LAST_ACK: 該狀態是被動關閉一方在發送FIN報文後,最後等待對方的ACK報文。當收到ACK報文後,即可以進入到CLOSED可用狀態。

半關閉

  • 當TCP鏈接中A發送FIN請求關閉,B端回應ACK後(A端進入FIN_WAIT_2狀態),B沒有立即發送FIN給A時,A方處在半鏈接狀態,此時A可以接收B發送的數據,但是A已不能再向B發送數據。

  • 從程式的角度,可以使用API來控制實現半連接狀態。

    #include <sys/socket.h>
    int shutdown(int sockfd, int how);
    sockfd: 需要關閉的socket的描述符
    how:    允許為shutdown操作選擇以下幾種方式:
        SHUT_RD(0): 關閉sockfd上的讀功能,此選項將不允許sockfd進行讀操作。
                        該套接字不再接受數據,任何當前在套接字接受緩衝區的數據將被無聲的丟棄掉。
        SHUT_WR(1):     關閉sockfd的寫功能,此選項將不允許sockfd進行寫操作。進程不能在對此套接字發出寫操作。
        SHUT_RDWR(2):   關閉sockfd的讀寫功能。相當於調用shutdown兩次:首先是以SHUT_RD,然後以SHUT_WR。
    
  • 使用close中止一個連接,但它只是減少描述符的引用計數,並不直接關閉連接,只有當描述符的引用計數為0時才關閉連接。

  • shutdown不考慮描述符的引用計數,直接關閉描述符。也可選擇中止一個方向的連接,只中止讀或只中止寫。

  • 註意:

    • 1、如果有多個進程共用一個套接字,close每被調用一次,計數減1,直到計數為0時,也就是所用進程都調用了close,套接字將被釋放。
    • 2、在多進程中如果一個進程調用了shutdown(sfd, SHUT_RDWR)後,其它的進程將無法進行通信。但,如果一個進程close(sfd)將不會影響到其它進程。

2MSL

  • 2MSL (Maximum Segment Lifetime) TIME_WAIT狀態的存在有兩個理由:

    • (1)讓4次握手關閉流程更加可靠;4次握手的最後一個ACK是是由主動關閉方發送出去的,若這個ACK丟失,被動關閉方會再次發一個FIN過來。若主動關閉方能夠保持一個2MSL的TIME_WAIT狀態,則有更大的機會讓丟失的ACK被再次發送出去。
    • (2)防止lost duplicate對後續新建正常鏈接的傳輸造成破壞。lost uplicate在實際的網路中非常常見,經常是由於路由器產生故障,路徑無法收斂,導致一個packet在路由器A,B,C之間做類似死迴圈的跳轉。IP頭部有個TTL,限制了一個包在網路中的最大跳數,因此這個包有兩種命運,要麼最後TTL變為0,在網路中消失;要麼TTL在變為0之前路由器路徑收斂,它憑藉剩餘的TTL跳數終於到達目的地。但非常可惜的是TCP通過超時重傳機制在早些時候發送了一個跟它一模一樣的包,並先於它達到了目的地,因此它的命運也就註定被TCP協議棧拋棄。
  • 另外一個概念叫做incarnation connection,指跟上次的socket pair一摸一樣的新連接,叫做incarnation of previous connection。lost uplicate加上incarnation connection,則會對我們的傳輸造成致命的錯誤。

  • TCP是流式的,所有包到達的順序是不一致的,依靠序列號由TCP協議棧做順序的拼接;假設一個incarnation connection這時收到的seq=1000, 來了一個lost duplicate為seq=1000,len=1000, 則TCP認為這個lost duplicate合法,並存放入了receive buffer,導致傳輸出現錯誤。通過一個2MSL TIME_WAIT狀態,確保所有的lost duplicate都會消失掉,避免對新連接造成錯誤。

  • 該狀態為什麼設計在主動關閉這一方

    • (1)發最後ACK的是主動關閉一方。
    • (2)只要有一方保持TIME_WAIT狀態,就能起到避免incarnation connection在2MSL內的重新建立,不需要兩方都有。
  • 如何正確對待2MSL TIME_WAIT?

  • RFC要求socket pair在處於TIME_WAIT時,不能再起一個incarnation connection。但絕大部分TCP實現,強加了更為嚴格的限制。在2MSL等待期間,socket中使用的本地埠在預設情況下不能再被使用。

  • 若A 10.234.5.5 : 1234和B 10.55.55.60 : 6666建立了連接,A主動關閉,那麼在A端只要port為1234,無論對方的port和ip是什麼,都不允許再起服務。這甚至比RFC限制更為嚴格,RFC僅僅是要求socket pair不一致,而實現當中只要這個port處於TIME_WAIT,就不允許起連接。這個限制對主動打開方來說是無所謂的,因為一般用的是臨時埠;但對於被動打開方,一般是server,就悲劇了,因為server一般是熟知埠。比如http,一般埠是80,不可能允許這個服務在2MSL內不能起來。

  • 解決方案是給伺服器的socket設置SO_REUSEADDR選項,這樣的話就算熟知埠處於TIME_WAIT狀態,在這個埠上依舊可以將服務啟動。當然,雖然有了SO_REUSEADDR選項,但sockt pair這個限制依舊存在。比如上面的例子,A通過SO_REUSEADDR選項依舊在1234埠上起了監聽,但這時我們若是從B通過6666埠去連它,TCP協議會告訴我們連接失敗,原因為Address already in use.

  • RFC 793中規定MSL為2分鐘,實際應用中常用的是30秒,1分鐘和2分鐘等。

  • RFC (Request For Comments),是一系列以編號排定的文件。收集了有關網際網路相關資訊,以及UNIX和網際網路社群的軟體文件。

程式設計中的問題

  • 做一個測試,首先啟動server,然後啟動client,用Ctrl-C終止server,馬上再運行server,運行結果:

    itcast$ ./server
    bind error: Address already in use 
    
  • 這是因為,雖然server的應用程式終止了,但TCP協議層的連接並沒有完全斷開,因此不能再次監聽同樣的server埠。我們用netstat命令查看一下:

itcast$ netstat -apn |grep 6666 tcp 1 0 192.168.1.11:38103 192.168.1.11:6666 CLOSE_WAIT 3525/client 
tcp 0 0 192.168.1.11:6666 192.168.1.11:38103 FIN_WAIT2 - 
- server終止時,socket描述符會自動關閉併發FIN段給client,client收到FIN後處於CLOSE_WAIT狀態,但是client並沒有終止,也沒有關閉socket描述符,因此不會發FIN給server,因此server的TCP連接處於FIN_WAIT2狀態。

  • 現在用Ctrl-C把client也終止掉,再觀察現象: itcast$ netstat -apn |grep 6666 tcp 0 0 192.168.1.11:6666 192.168.1.11:38104 TIME_WAIT - itcast$ ./server bind error: Address already in use

  • client終止時自動關閉socket描述符,server的TCP連接收到client發的FIN段後處於TIME_WAIT狀態。TCP協議規定,主動關閉連接的一方要處於TIME_WAIT狀態,等待兩個MSL(maximum segment lifetime)的時間後才能回到CLOSED狀態,因為我們先Ctrl-C終止了server,所以server是主動關閉連接的一方,在TIME_WAIT期間仍然不能再次監聽同樣的server埠。

  • MSL在RFC 1122中規定為兩分鐘,但是各操作系統的實現不同,在Linux上一般經過半分鐘後就可以再次啟動server了。至於為什麼要規定TIME_WAIT的時間,可參考UNP 2.7節。

埠復用

  • 在server的TCP連接沒有完全斷開之前不允許重新監聽是不合理的。因為,TCP連接沒有完全斷開指的是connfd(127.0.0.1:6666)沒有完全斷開,而我們重新監聽的是lis-tenfd(0.0.0.0:6666),雖然是占用同一個埠,但IP地址不同,connfd對應的是與某個客戶端通訊的一個具體的IP地址,而listenfd對應的是wildcard address。解決這個問題的方法是使用setsockopt()設置socket描述符的選項SO_REUSEADDR為1,表示允許創建埠號相同但IP地址不同的多個socket描述符。

  • 在server代碼的socket()和bind()調用之間插入如下代碼: int opt = 1; setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

  • 有關setsockopt可以設置的其它選項請參考UNP第7章。

TCP異常斷開

心跳檢測機制

  • 在TCP網路通信中,經常會出現客戶端和伺服器之間的非正常斷開,需要實時檢測查詢鏈接狀態。常用的解決方法就是在程式中加入心跳機制。

  • Heart-Beat線程

  • 這個是最常用的簡單方法。在接收和發送數據時個人設計一個守護進程(線程),定時發送Heart-Beat包,客戶端/伺服器收到該小包後,立刻返回相應的包即可檢測對方是否實時線上。

  • 該方法的好處是通用,但缺點就是會改變現有的通訊協議!大家一般都是使用業務層心跳來處理,主要是靈活可控。

  • UNIX網路編程不推薦使用SO_KEEPALIVE來做心跳檢測,還是在業務層以心跳包做檢測比較好,也方便控制。

設置TCP屬性

  • SO_KEEPALIVE 保持連接檢測對方主機是否崩潰,避免(伺服器)永遠阻塞於TCP連接的輸入。設置該選項後,如果2小時內在此套介面的任一方向都沒有數據交換,TCP就自動給對方發一個保持存活探測分節(keepalive probe)。這是一個對方必須響應的TCP分節.它會導致以下三種情況:對方接收一切正常:以期望的ACK響應。2小時後,TCP將發出另一個探測分節。對方已崩潰且已重新啟動:以RST響應。套介面的待處理錯誤被置為ECONNRESET,套接 口本身則被關閉。對方無任何響應:源自berkeley的TCP發送另外8個探測分節,相隔75秒一個,試圖得到一個響應。在發出第一個探測分節11分鐘 15秒後若仍無響應就放棄。套介面的待處理錯誤被置為ETIMEOUT,套介面本身則被關閉。如ICMP錯誤是“host unreachable(主機不可達)”,說明對方主機並沒有崩潰,但是不可達,這種情況下待處理錯誤被置為EHOSTUNREACH。

  • 根據上面的介紹我們可以知道對端以一種非優雅的方式斷開連接的時候,我們可以設置SO_KEEPALIVE屬性使得我們在2小時以後發現對方的TCP連接是否依然存在。 keepAlive = 1; setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));

  • 如果我們不能接受如此之長的等待時間,從TCP-Keepalive-HOWTO上可以知道一共有兩種方式可以設置,一種是修改內核關於網路方面的 配置參數,另外一種就是SOL_TCP欄位的TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT三個選項。

  • 1.The tcp_keepidle parameter specifies the interval of inactivity that causes TCP to generate a KEEPALIVE transmission for an application that requests them. tcp_keepidle defaults to 14400 (two hours).

    /*開始首次KeepAlive探測前的TCP空閉時間 */
    
  • 2.The tcp_keepintvl parameter specifies the interval between the nine retriesthat are attempted if a KEEPALIVE transmission is not acknowledged. tcp_keep ntvldefaults to 150 (75 seconds).

    /* 兩次KeepAlive探測間的時間間隔 */
    
  • 3.The tcp_keepcnt option specifies the maximum number of keepalive probes tobe sent. The value of TCP_KEEPCNT is an integer value between 1 and n, where n s the value of the systemwide tcp_keepcnt parameter.

    /* 判定斷開前的KeepAlive探測次數*/
    
    int keepIdle = 1000;
    int keepInterval = 10;
    int keepCount = 10;
    
    Setsockopt(listenfd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
    Setsockopt(listenfd, SOL_TCP,TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
    Setsockopt(listenfd,SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
    
  • SO_KEEPALIVE設置空閑2小時才發送一個“保持存活探測分節”,不能保證實時檢測。對於判斷網路斷開時間太長,對於需要及時響應的程式不太適應。

  • 當然也可以修改時間間隔參數,但是會影響到所有打開此選項的套介面!關聯了完成埠的socket可能會忽略掉該套接字選項。

網路名詞術語解析

路由(route)

  • 路由(名詞)
    • 數據包從源地址到目的地址所經過的路徑,由一系列路由節點組成。
  • 路由(動詞)
    • 某個路由節點為數據包選擇投遞方向的選路過程。

路由器工作原理

  • 路由器(Router)是連接網際網路中各區域網、廣域網的設備,它會根據通道的情況自動選擇和設定路由,以最佳路徑,按前後順序發送信號的設備。

  • 傳統地,路由器工作於OSI七層協議中的第三層,其主要任務是接收來自一個網路介面的數據包,根據其中所含的目的地址,決定轉發到下一個目的地址。因此,路由器首先得在轉發路由表中查找它的目的地址,若找到了目的地址,就在數據包的幀格前添加下一個MAC地址,同時IP數據包頭的TTL(Time To Live)域也開始減數, 並重新計算校驗和。當數據包被送到輸出埠時,它需要按順序等待,以便被傳送到輸出鏈路上。

  • 路由器在工作時能夠按照某種路由通信協議查找設備中的路由表。如果到某一特定節點有一條以上的路徑,則基本預先確定的路由準則是選擇最優(或最經濟)的傳輸路徑。由於各種網路段和其相互連接情況可能會因環境變化而變化,因此路由情況的信息一般也按所使用的路由信息協議的規定而定時更新。

  • 網路中,每個路由器的基本功能都是按照一定的規則來動態地更新它所保持的路由表,以便保持路由信息的有效性。為了便於在網路間傳送報文,路由器總是先按照預定的規則把較大的數據分解成適當大小的數據包,再將這些數據包分別通過相同或不同路徑發送出去。當這些數據包按先後秩序到達目的地後,再把分解的數據包按照一定順序包裝成原有的報文形式。路由器的分層定址功能是路由器的重要功能之一,該功能可以幫助具有很多節點站的網路來存儲定址信息,同時還能在網路間截獲發送到遠地網段的報文,起轉發作用;選擇最合理的路由,引導通信也是路由器基本功能;多協議路由器還可以連接使用不同通信協議的網路段,成為不同通信協議網路段之間的通信平臺。

  • 路由和交換之間的主要區別就是交換髮生在OSI參考模型第二層(數據鏈路層),而路由發生在第三層,即網路層。這一區別決定了路由和交換在移動信息的過程 中需使用不同的控制信息,所以兩者實現各自功能的方式是不同的。

路由表(Routing Table)

  • 在電腦網路中,路由表或稱路由擇域信息庫(RIB)是一個存儲在路由器或者聯網電腦中的電子錶格(文件)或類資料庫。路由表存儲著指向特定網路地址的路徑。

路由條目

  • 路由表中的一行,每個條目主要由目的網路地址、子網掩碼、下一跳地址、發送介面四部分組成,如果要發送的數據包的目的網路地址匹配路由表中的某一行,就按規定的介面發送到下一跳地址。

預設路由條目

  • 路由表中的最後一行,主要由下一跳地址和發送介面兩部分組成,當目的地址與路由表中其它行都不匹配時,就按預設路由條目規定的介面發送到下一跳地址。

路由節點

  • 一個具有路由能力的主機或路由器,它維護一張路由表,通過查詢路由表來決定向哪個介面發送數據包。

乙太網交換機工作原理

  • 乙太網交換機是基於乙太網傳輸數據的交換機,乙太網採用共用匯流排型傳輸媒體方式的區域網。乙太網交換機的結構是每個埠都直接與主機相連,並且一般都工作在全雙工方式。交換機能同時連通許多對埠,使每一對相互通信的主機都能像獨占通信媒體那樣,進行無衝突地傳輸數據。

  • 乙太網交換機工作於OSI網路參考模型的第二層(即數據鏈路層),是一種基於MAC(Media Access Control,介質訪問控制)地址識別、完成乙太網數據幀轉發的網路設備。

hub工作原理

  • 集線器實際上就是中繼器的一種,其區別僅在於集線器能夠提供更多的埠服務,所以集線器又叫多口中繼器。

  • 集線器功能是隨機選出某一埠的設備,並讓它獨占全部帶寬,與集線器的上聯設備(交換機、路由器或伺服器等)進行通信。從Hub的工作方式可以看出,它在網路中只起到信號放大和重發作用,其目的是擴大網路的傳輸範圍,而不具備信號的定向傳送能力,是—個標準的共用式設備。其次是Hub只與它的上聯設備(如上層Hub、交換機或伺服器)進行通信,同層的各埠之間不會直接進行通信,而是通過上聯設備再將信息廣播到所有埠上。 由此可見,即使是在同一Hub的不同兩個埠之間進行通信,都必須要經過兩步操作:

  • 第一步是將信息上傳到上聯設備;

  • 第二步是上聯設備再將該信息廣播到所有埠上。

半雙工/全雙工

  • Full-duplex(全雙工)全雙工是在通道中同時雙向數據傳輸的能力。
  • Half-duplex(半雙工)在通道中同時只能沿著一個方向傳輸數據。

DNS伺服器

  • DNS 是功能變數名稱系統 (Domain Name System) 的縮寫,是網際網路的一項核心服務,它作為可以將功能變數名稱和IP地址相互映射的一個分散式資料庫,能夠使人更方便的訪問互聯網,而不用去記住能夠被機器直接讀取的IP地址串。

  • 它是由解析器以及功能變數名稱伺服器組成的。功能變數名稱伺服器是指保存有該網路中所有主機的功能變數名稱和對應IP地址,並具有將功能變數名稱轉換為IP地址功能的伺服器。

區域網(LAN)

  • local area network,一種覆蓋一座或幾座大樓、一個校園或者一個廠區等地理區域的小範圍的電腦網。
  • 1、覆蓋的地理範圍較小,只在一個相對獨立的局部範圍內聯,如一座或集中的建築群內。
  • 2、使用專門鋪設的傳輸介質進行聯網,數據傳輸速率高(10Mb/s~10Gb/s)
  • 3、通信延遲時間短,可靠性較高
  • 4、區域網可以支持多種傳輸介質

廣域網(WAN)

  • wide area network,一種用來實現不同地區的區域網或城域網的互連,可提供不同地區、城市和國家之間的電腦通信的遠程電腦網。

  • 覆蓋的範圍比區域網(LAN)和城域網(MAN)都廣。廣域網的通信子網主要使用分組交換技術。

  • 廣域網的通信子網可以利用公用分組交換網、衛星通信網和無線分組交換網,它將分佈在不同地區的區域網或電腦系統互連起來,達到資源共用的目的。如互聯網是世界範圍內最大的廣域網。

  • 1、適應大容量與突發性通信的要求;
  • 2、適應綜合業務服務的要求;
  • 3、開放的設備介面與規範化的協議;
  • 4、完善的通信服務與網路管理。

  • 邏輯意義上的埠,一般是指TCP/IP協議中的埠,埠號的範圍從0到65535,比如用於瀏覽網頁服務的80埠,用於FTP服務的21埠等等。
  • 1、埠號小於256的定義為常用埠,伺服器一般都是通過常用埠號來識別的。
  • 2、客戶端只需保證該埠號在本機上是惟一的就可以了。客戶埠號因存在時間很短暫又稱臨時埠號;
  • 3、大多數TCP/IP實現給臨時埠號分配1024—5000之間的埠號。大於5000的埠號是為其他伺服器預留的。
  • 我們應該在自定義埠時,避免使用well-known的埠。如:80、21等等。

MTU

  • MTU:通信術語 最大傳輸單元(Maximum Transmission Unit,MTU)
  • 是指一種通信協議的某一層上面所能通過的最大數據包大小(以位元組為單位)。最大傳輸單元這個參數通常與通信介面有關(網路介面卡、串口等)。
  • 以下是一些協議的MTU:

    FDDI協議:4352位元組
    乙太網(Ethernet)協議:1500位元組
    PPPoE(ADSL)協議:1492位元組
    X.25協議(Dial Up/Modem):576位元組
    Point-to-Point:4470位元組
    

常見網路知識面試題

  • 1、TCP如何建立鏈接
  • 2、TCP如何通信
  • 3、TCP如何關閉鏈接
  • 4、什麼是滑動視窗
  • 5、什麼是半關閉
  • 6、區域網內兩台機器如何利用TCP/IP通信
  • 7、internet上兩台主機如何進行通信
  • 8、如何在internet上識別唯一一個進程
    • 答:通過“IP地址+埠號”來區分不同的服務
  • 9、為什麼說TCP是可靠的鏈接,UDP不可靠
  • 10、路由器和交換機的區別
  • 11、點到點,端到端

Socket編程

套接字概念

  • Socket本身有“插座”的意思,在Linux環境下,用於表示進程間網路通信的特殊文件類型。本質為內核藉助緩衝區形成的偽文件。

  • 既然是文件,那麼理所當然的,我們可以使用文件描述符引用套接字。與管道類似的,Linux系統將其封裝成文件的目的是為了統一介面,使得讀寫套接字和讀寫文件的操作一致。區別是管道主要應用於本地進程間通信,而套接字多應用於網路進程間數據的傳遞。

  • 套接字的內核實現較為複雜,不宜在學習初期深入學習。

  • 在TCP/IP協議中,“IP地址+TCP或UDP埠號”唯一標識網路通訊中的一個進程。“IP地址+埠號”就對應一個socket。欲建立連接的兩個進程各自有一個socket來標識,那麼這兩個socket組成的socket pair就唯一標識一個連接。因此可以用Socket來描述網路連接的一對一關係。

  • 套接字通信原理如下圖所示:

套接字通訊原理示意

  • 在網路通信中,套接字一定是成對出現的。一端的發送緩衝區對應對端的接收緩衝區。我們使用同一個文件描述符索發送緩衝區和接收緩衝區。

  • TCP/IP協議最早在BSD UNIX上實現,為TCP/IP協議設計的應用層編程介面稱為socket API。本章的主要內容是socket API,主要介紹TCP協議的函數介面,最後介紹UDP協議和UNIX Domain Socket的函數介面。

網路編程介面

預備知識

網路位元組序

  • 我們已經知道,記憶體中的多位元組數據相對於記憶體地址有大端和小端之分,磁碟文件中的多位元組數據相對於文件中的偏移地址也有大端小端之分。網路數據流同樣有大端小端之分,那麼如何定義網路數據流的地址呢?發送主機通常將發送緩衝區中的數據按記憶體地址從低到高的順序發出,接收主機把從網路上接到的位元組依次保存在接收緩衝區中,也是按記憶體地址從低到高的順序保存,因此,網路數據流的地址應這樣規定:先發出的數據是低地址,後發出的數據是高地址。

  • TCP/IP協議規定,網路數據流應採用大端位元組序,即低地址高位元組。例如上一節的UDP段格式,地址0-1是16位的源埠號,如果這個埠號是1000(0x3e8),則地址0是0x03,地址1是0xe8,也就是先發0x03,再發0xe8,這16位在發送主機的緩衝區中也應該是低地址存0x03,高地址存0xe8。但是,如果發

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Java,C#已經比較熟悉,最近在從0開始自學C++。學習過程中必然會與Java,C#進行對比,有吐槽,也有點贊。 先來講講最基本也是最重要的部分:參數傳遞的方式。 對於類型, Java分基本類型、複合類型,從另外一個角度分是值類型,引用類型。在展開對比前, 我們先來看看三個關鍵方式: 值 創建新的 ...
  • JDK、JRE、JVM JDK包含JRE,而JRE包含JVM JDK(Java Development Kit)是針對Java開發員的產品,是整個Java的核心,包括了Java運行環境JRE、Java工具和Java基礎類庫。Java Runtime Environment(JRE)是運行JAVA程式 ...
  • 我安裝的是Myeclipse 10.7.1。裝上好久沒用,今天啟動突然報錯:Failed to create the Java Virtual Machine。 檢查Myeclipse安裝好使用時好的啊,近期也沒用,可能是近期升級了本地單獨安裝的jre版本導致的吧(Myeclipse使用自己的jre... ...
  • 歡迎任何形式的轉載,但請務必註明出處。 1.jdk安裝及環境配置 點擊進入教程 2.Eclipse安裝 點擊進入官網下載 註意下載完成打開.exe後,出現的界面,有很多版本供選擇。選擇下圖版本 3.Tomcat安裝及環境配置 點擊進入教程 4.配置Tomcat伺服器 註意我下載的是V9.0版本,根據 ...
  • Java程式員編程時需要混合面向對象思維和一般命令式編程的方法,能否完美的將兩者結合起來完全得依靠編程人員的水準: 技能(任何人都能容易學會命令式編程) 模式(有些人用“模式-模式”,舉個例子,模式可以應用到任何地方,而且都可以歸為某一類模式) 心境(首先,要寫個好的面向對象程式是比命令式程式難的多 ...
  • Java語言基礎之常量: 概念: 在程式執行中,其值不可發生改變的量,稱為常量 常量在程式運行過程中主要有兩個作用: 1.代表常數,便於常數的修改; 2.增強程式的可讀性。 常量的分類: 字面值常量 自定義常量(面向對象部分講) 字面值常量的分類: 1. 整型常量:整型常量的值為整數的類型,它可以採 ...
  • 題目大意: 在n*n(n<=512)的網格上,從邊界某個點出發,經過每個點一次且回到邊界上,構造出一種方案使拐彎的數量至少為n*(n-1)-1次。 構造方法:我們可以手算出n=2~6時的方案。 n=2: n=3: n=4: n=5: n=6: 觀察n=2與n=4、n=3與n=5的情況我們可以得到一種 ...
  • <! TOC "algorithmn" "parameter" "code" "主要是以下三個函數" "計算所有的可行點" "怎麼計算一個點的可行點" "從可行點中計算路徑path" "todo" <! /TOC algorithmn "演算法的解釋" "Dijkstra" 其實就是A star或者D ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...