4、TCP/IP通信原理


 1、TCP/IP協議族

  TCP/IP 是供已連接因特網的計算機進行通信的通信協議。
  TCP/IP 指傳輸控制協議/網際協議(Transmission Control Protocol / Internet Protocol)。
  TCP/IP 定義了電子設備(比如計算機)如何連入因特網,以及數據如何在它們之間傳輸的標准。
  TCP/IP 通信協議是對計算機必須遵守的規則的描述,只有遵守這些規則,計算機之間才能進行通信。

  目前使用的網絡模型都是 TCP/IP 模型,它是對 OSI 模型進行了簡化,只包含了四層,從上到下分別是應用層、傳輸層、網絡層和鏈路層(網絡接口層),每一層都包含了若干協議。

  TCP/IP 模型包含了 TCP、IP、UDP、Telnet、FTP、SMTP 等上百個互為關聯的協議,其中 TCP 和 IP 是最常用的兩種底層協議,所以把它們統稱為“TCP/IP 協議族”。

  也就是說,“TCP/IP模型”中所涉及到的協議稱為“TCP/IP協議族”,你可以區分這兩個概念,也可以認為它們是等價的。

  TCP/IP 是一個復雜的協議族,它是由一組專業化協議組成的,其中包含ftp、http、tcp、udp、ip、icmp、dns等。
    常用協議:
    TCP:用來檢測網絡傳輸中差錯的傳輸控制協議
    IP:專門負責對不同網絡進行互聯的互聯網協議
    UDP:用戶數據報協議
    ICMP:互聯網控制信息協議
    SMTP:簡單郵件傳輸協議
    SNMP:簡單網絡管理協議
    HTTP:超文本傳輸協議
    FTP:文件傳輸協議
    ARP:地址解析協議

  我們所說的 socket 編程是基於 TCP 和 UDP 協議的,是站在傳輸層的基礎上,所以可以使用 TCP/UDP 協議,但是不能干「訪問網頁」這樣的事情,因為訪問網頁所需要的 http 協議位於應用層。它們的層級關系如下圖所示:

 

 

 

 

 

 

 

 

 

 

 

 

  把協議分成多個層次有哪些優點?協議設計更容易?當然這也足以成為優點之一。但是還有更重要的原因,就是為了通過標准化操作設計成開放式系統。

  標准本身就是對外公開的,會引導更多的人遵守規范。以多個標准為依據設計的系統稱為開放式系統(Open System),我們現在學習的 TCP/IP 協議族也屬於其中之一。

  開放式系統的優點:
  路由器用來完成 IP 層的交互任務。某個網絡原來使用 A 公司的路由器,現要將其替換成 B 公司的,是否可行?這並非難事,並不一定要換成同一公司的同一型號路由器,因為所有生產商都會按照 IP 層標准制造。
  再舉個例子。大家的計算機是否裝有網絡接口卡,也就是所謂的網卡?尚未安裝也無妨,其實很容易買到,因為所有網卡制造商都會遵守鏈路層的協議標准。這就是開放式系統的優點。
  標准的存在意味着高速的技術發展,這也是開放式系統設計最大的原因所在。實際上,軟件工程中的“面向對象(Object Oriented)”的誕生背景中也有標准化的影子。也就是說,標准對於技術發展起着舉足輕重的作用。

2、TCP和UDP

  在TCP/IP協議族中有很多協議,TCP/IP協議群中的核心協議被設計在網絡層和傳輸層,他們為網絡中的各主機提供通信服務,也為模型的最高層(應用層)中的協議提供服務。

  2.1、TCP

  TCP向應用層提供可靠的面向連接的數據流傳輸服務。他能提供高可靠性通信(即數據無誤、數據無丟失、數據無失序、數據無重復到達)。

  通過源/目的IP可以唯一的區分網絡中的兩個設備,在通過源/目的端口可以唯一的區分網絡中兩個通信的應用程序。

  2.1.1、TCP數據包結構

 

 

 

 

 

 

 

 

 

 

  

  (1)源端口:16bit,本地端口號

  (2)目標端口:16bit,遠端的端口號

  (3)順序號(Seq):32bit,Seq(Sequence Number)用來標識從計算機A發送到計算機B的數據包的順序,即數據包的序號,注意,這個序號不是按1遞增的,而是按tcp包內數據字節長度加上,比如包內數據是21字節,而當前計算機A發到計算機B的包的seq是10的話,那下個計算機1發送到計算機2的包的seq就是10+21=31,

  (4)確認號(Ack):32bit,Ack(Acknowledge Number)表示希望收到的下一個數據包的序列號,客戶端和服務器端都可以發送,Ack = Seq + 1。

  (5)首部長度:4bit,用來表示TCP頭中包含多少個32bit

  (6)保留:6bit未用

  (7)標志位:每個標志位占用1Bit,共有6個,分別為 URG、ACK、PSH、RST、SYN、FIN,具體含義如下:
        URG:緊急指針(urgent pointer)有效。
        ACK:確認序號有效。ACK位置1表示確認號是合法的;如果ACK為0,那么數據包就不包含確認信息,確認字段被省略。
        PSH:表示是帶有PUSH標志的數據。因此請求數據包一到接收方便可送往應用程序而不必等到緩沖區裝滿時才傳送。接收方應該盡快將這個報文交給應用層。
        RST:重置連接。用於復位由於主機崩潰或其它原因而出現的錯誤的連接,還可以用於拒絕非法的數據包或拒絕連接請求。
        SYN:建立一個新連接。
        FIN:斷開一個連接。

  (8)窗口:16bit',窗口用來表示在確認了字節數之后還可以發送多少字節

  (9)校驗和:16bit,是為了確保高可靠性而設置的,它校驗頭部和數據之和

  (10)可選項:0或32bit,包括最大TCP載荷、窗口比例、選擇重發數據包等選項

  Seq 是 Sequence 的縮寫,表示序列;Ack(ACK) 是 Acknowledge 的縮寫,表示確認;SYN 是 Synchronous 的縮寫,願意是“同步的”,這里表示建立同步連接;FIN 是 Finish 的縮寫,表示完成。

  2.1.2、TCP套接字中的I/O緩沖

  TCP套接字的數據收發無邊界性,即使服務器端調用1次write()函數傳輸100字節的數據,客戶端也有可能通過調用10次read()函數,每次讀取10個字節來讀取這100個字節的數據。那么在第一次讀取10個字節的時候,剩下的90字節在什么地方了,這就需要I/O緩沖。

  write()函數在調用之后並非立即傳輸數據,read()函數調用后也並非馬上接收數據。在調用write()函數之后,數據將移至輸出緩沖;在調用read()函數時,從輸入緩沖中讀取數據。

  如上圖所示,調用write()函數時,數據將移至輸出緩沖,在適當的時候傳向對方的輸入緩沖,這時對方將調用read()函數從輸入緩沖中讀取數據。

  這些I/O緩沖特性如下:
    I/O緩沖在每個TCP套接字中單獨存在;
    I/O緩沖在創建套接字時自動生產;
    即使關閉套接字也會繼續傳輸緩沖區中遺留的數據;
    關閉套接字將丟失輸入緩沖區中的數據。

  2.1.3、三次握手協議

  TCP是一種面向連接的、可靠的、基於字節流的通信協議。所謂面向連接,就是數據在傳輸前要建立連接,然后進行數據數據傳輸,傳輸完畢后還要斷開連接。

  客戶端在收發數據前要使用 connect() 函數和服務器建立連接。建立連接的目的是保證IP地址、端口、物理鏈路等正確無誤,為數據的傳輸開辟通道。

  套接字十一全雙工方式工作的,也就是說,它可以雙向傳遞數據。因此收發數據前需要做一些准備。

  TCP建立連接時要傳輸三個數據包,俗稱三次握手(Three-way Handshaking)。可以形象的比喻為下面的對話:

    [Shake 1] 套接字A:“你好,套接字B,我這里有數據要傳送給你,建立連接吧。”
    [Shake 2] 套接字B:“好的,我這邊已准備就緒。”
    [Shake 3] 套接字A:“謝謝你受理我的請求。”

  使用 connect() 建立連接時,客戶端和服務器端會相互發送三個數據包,請看下圖:

 

 

  客戶端調用 socket() 函數創建套接字后,因為沒有建立連接,所以套接字處於CLOSED狀態;服務器端調用 listen() 函數后,套接字進入LISTEN狀態,開始監聽客戶端請求。

  這個時候,客戶端開始發起請求:

  第1步:當客戶端調用 connect() 函數后,TCP協議會組建一個數據包,並設置 SYN 標志位,表示該數據包是用來建立同步連接的。同時生成一個隨機數字Seq=1000(1000表示客戶端現在傳遞的數據包序號為1000,如果服務器接收無誤,請服務器通知客戶端向服務器傳遞1001號數據包),填充“序號(Seq)”字段,表示該數據包的序號,Ack為空。完成這些工作,開始向服務器端發送數據包,客戶端就進入了SYN_SEND狀態,等待服務器的確認。這是首次請求連接時使用的消息,又稱SYN。SYN是Synchronization的簡寫,表示收發數據前傳輸的同步消息。

  第2步:服務器端收到數據包,檢測到已經設置了 SYN 標志位,就知道這是客戶端發來的建立連接的“請求包”。服務器端也會組建一個數據包,並設置 SYN 和 ACK 標志位,SYN 表示該數據包用來建立連接,ACK 用來回復客戶端收到了剛才發送的數據包。此時服務器進入SYN_RECV狀態。

  服務器生成一個隨機數Seq=2000(2000表示服務器端現在傳遞的數據包序號為2000,如果客戶端接收無誤,請客戶端通知服務器向客戶端傳遞2001號數據包),填充“序號(Seq)”字段。2000 和客戶端數據包沒有關系。
  服務器將客戶端數據包序號(1000)加1,得到1001(通知客戶端剛才傳輸的Seq為1000的數據包接收無誤,現在請傳遞Seq為1001的數據包),並用這個數字填充“確認號(Ack)”字段。
  服務器將數據包發出,進入SYN-RECV狀態。

  服務器對客戶端首次傳輸的數據包的確認消息(Ack=1001)和為主機B傳輸數據做准備的同步消息(Seq 2000)捆綁發送,因此,此種的消息又稱為SYN+ACK。

  收發數據前向數據包分配序號,並向對方通報此序號,這都是為防止數據丟失所做的准備。通過向數據包分配序號並確認,可以在數據丟失時馬上查看並重傳丟失的數據包。因此,TCP可以保證可靠地數據傳輸。

  第3步:客戶端收到數據包,檢測到已經設置了 SYN 和 ACK 標志位,就知道這是服務器發來的“確認包”。客戶端會檢測“確認號(Ack)”字段,看它的值是否為 1000+1,如果是就說明連接建立成功。
  接下來,客戶端會繼續組建數據包,並設置 ACK 標志位,表示客戶端正確接收了服務器發來的“確認包”。將Seq設置為1001,同時,將剛才服務器發來的數據包序號(2000)加1,得到 2001,並用這個數字來填充“確認號(Ack)”字段。
  客戶端將數據包發出,進入ESTABLISED狀態,表示連接已經成功建立。

  第4步:服務器端收到數據包,檢測到已經設置了 ACK 標志位,就知道這是客戶端發來的“確認包”。服務器會檢測“確認號(Ack)”字段,看它的值是否為 2000+1,如果是就說明連接建立成功,服務器進入ESTABLISED狀態。
至此,客戶端和服務器都進入了ESTABLISED狀態,連接建立成功,接下來就可以收發數據了。

    三次握手的關鍵是要確認對方收到了自己的數據包,這個目標就是通過“確認號(Ack)”字段實現的。計算機會記錄下自己發送的數據包序號 Seq,待收到對方的數據包后,檢測“確認號(Ack)”字段,看Ack = Seq + 1是否成立,如果成立說明對方正確收到了自己的數據包。

  2.1.4、傳輸數據

  建立連接后,兩台主機就可以相互傳輸數據了。如下圖所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  上圖給出了主機A分2次(分2個數據包)向主機B傳遞200字節的過程。首先,主機A通過1個數據包發送100個字節的數據,數據包的 Seq 號設置為 1200。主機B為了確認這一點,向主機A發送 ACK 包,並將 Ack 號設置為 1301。

  為了保證數據准確到達,目標機器在收到數據包(包括SYN包、FIN包、普通數據包等)包后必須立即回傳ACK包,這樣發送方才能確認數據傳輸成功。

  此時 Ack 號為 1301 而不是 1201,原因在於 Ack 號的增量為傳輸的數據字節數。假設每次 Ack 號不加傳輸的字節數,這樣雖然可以確認數據包的傳輸,但無法明確100字節全部正確傳遞還是丟失了一部分,比如只傳遞了80字節。因此按如下的公式確認 Ack 號:Ack號 = Seq號 + 傳遞的字節數 + 1

  與三次握手協議相同,最后加 1 是為了告訴對方要傳遞的 Seq 號。

下面分析傳輸過程中數據包丟失的情況,如下圖所示:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  上圖表示通過 Seq 1301 數據包向主機B傳遞100字節的數據,但中間發生了錯誤,主機B未收到。經過一段時間后,主機A仍未收到對於 Seq 1301 的ACK確認,因此嘗試重傳數據。

  為了完成數據包的重傳,TCP套接字每次發送數據包時都會啟動定時器,如果在一定時間內沒有收到目標機器傳回的 ACK 包,那么定時器超時,數據包會重傳。

  上圖演示的是數據包丟失的情況,也會有 ACK 包丟失的情況,一樣會重傳。

  (1)、重傳超時時間(RTO, Retransmission Time Out)
  這個值太大了會導致不必要的等待,太小會導致不必要的重傳,理論上最好是網絡 RTT 時間,但又受制於網絡距離與瞬態時延變化,所以實際上使用自適應的動態算法(例如 Jacobson 算法和 Karn 算法等)來確定超時時間。

  往返時間(RTT,Round-Trip Time)表示從發送端發送數據開始,到發送端收到來自接收端的 ACK 確認包(接收端收到數據后便立即確認),總共經歷的時延。

  (2)、重傳次數
  TCP數據包重傳次數根據系統設置的不同而有所區別。有些系統,一個數據包只會被重傳3次,如果重傳3次后還未收到該數據包的 ACK 確認,就不再嘗試重傳。但有些要求很高的業務系統,會不斷地重傳丟失的數據包,以盡最大可能保證業務數據的正常交互。

  最后需要說明的是,發送端只有在收到對方的 ACK 確認包后,才會清空輸出緩沖區中的數據。

  2.1.5、四次揮手

  建立連接非常重要,它是數據正確傳輸的前提;斷開連接同樣重要,它讓計算機釋放不再使用的資源。如果連接不能正常斷開,不僅會造成數據傳輸錯誤,還會導致套接字不能關閉,持續占用資源,如果並發量高,服務器壓力堪憂。

  建立連接需要三次握手,斷開連接需要四次揮手,可以形象的比喻為下面的對話:
      [Shake 1] 套接字A:“任務處理完畢,我希望斷開連接。”
      [Shake 2] 套接字B:“哦,是嗎?請稍等,我准備一下。”
      等待片刻后……
      [Shake 3] 套接字B:“我准備好了,可以斷開連接了。”
      [Shake 4] 套接字A:“好的,謝謝合作。”

  下圖演示了客戶端主動斷開連接的場景:

 

  建立連接后,客戶端和服務器都處於ESTABLISED狀態。這時,客戶端發起斷開連接的請求:
  (1)客戶端調用 close() 函數后,向服務器發送 FIN 數據包,進入FIN_WAIT_1狀態。FIN 是 Finish 的縮寫,表示完成任務需要斷開連接。
  (2)服務器收到數據包后,檢測到設置了 FIN 標志位,知道要斷開連接,於是向客戶端發送“確認包”,進入CLOSE_WAIT狀態。
  注意:服務器收到請求后並不是立即斷開連接,而是先向客戶端發送“確認包”,告訴它我知道了,我需要准備一下才能斷開連接。
  (3)客戶端收到“確認包”后進入FIN_WAIT_2狀態,等待服務器准備完畢后再次發送數據包。
  (4)等待片刻后,服務器准備完畢,可以斷開連接,於是再主動向客戶端發送 FIN 包,告訴它我准備好了,斷開連接吧。然后進入LAST_ACK狀態。
  (5)客戶端收到服務器的 FIN 包后,再向服務器發送 ACK 包,告訴它你斷開連接吧。然后進入TIME_WAIT狀態。
  (6) 服務器收到客戶端的 ACK 包后,就斷開連接,關閉套接字,進入CLOSED狀態。

  關於 TIME_WAIT 狀態的說明:
  客戶端最后一次發送 ACK包后進入 TIME_WAIT 狀態,而不是直接進入 CLOSED 狀態關閉連接,這是為什么呢?

  TCP 是面向連接的傳輸方式,必須保證數據能夠正確到達目標機器,不能丟失或出錯,而網絡是不穩定的,隨時可能會毀壞數據,所以機器A每次向機器B發送數據包后,都要求機器B”確認“,回傳ACK包,告訴機器A我收到了,這樣機器A才能知道數據傳送成功了。如果機器B沒有回傳ACK包,機器A會重新發送,直到機器B回傳ACK包。

  客戶端最后一次向服務器回傳ACK包時,有可能會因為網絡問題導致服務器收不到,服務器會再次發送 FIN 包,如果這時客戶端完全關閉了連接,那么服務器無論如何也收不到ACK包了,所以客戶端需要等待片刻、確認對方收到ACK包后才能進入CLOSED狀態。那么,要等待多久呢?

  超過這個時間還未到達目標主機就會被丟棄,並通知源主機。這稱為報文最大生存時間(MSL,Maximum Segment Lifetime)。TIME_WAIT 要等待 2MSL 才會進入 CLOSED 狀態。ACK 包到達服務器需要 MSL 時間,服務器重傳 FIN 包也需要 MSL 時間,2MSL 是數據包往返的最大時間,如果 2MSL 后還未收到服務器重傳的 FIN 包,就說明服務器已經收到了 ACK 包。

  2.2、UDP

  UDP即用戶數據報協議,是一種面向無連接的不可靠傳輸協議,具有資源消耗小、處理速度快的特點。

  由於UDP通信之前不需要先建立一個連接,因此UDP應用要比TCP應用更加簡單。UDP比TCP更為高效,也能更好的解決實時性的問題。目前為止,包括網絡視頻會議系統在內的眾多的客戶/服務器模式的網絡應用都使用UDP。

  如果只考慮可靠性,TCP的確比UDP好。但UDP在結構上比TCP更簡潔。UDP不會發送類似ACK的應答消息,也不會像SEQ那樣給數據包分配序號。因此,UDP的性能有時比TCP高出很多。編程中實現UDP也比TCP簡單。另外,UDP的可靠性雖然比不上TCP,但也不會像想象中那么頻繁的發生數據損壞。因此,在更重視性能而非可靠性的情況下,UDP是一種很好的選擇。

  為了提供可靠的數據傳輸服務,TCP在不可靠的IP層進行流控制,而UDP就缺少這種流控制機制。流控制是區分TCP和UDP的最重要的標志。但如果從TCP中除去流控制,所剩內容也屈指可數。也就是說,TCP的生命在於流控制。

  UDP數據包結構

  (1)源端口:16bit,標識出本地的端口號

  (2)目標端口:16bit,標識出遠端的端口號

  (3)數據包的長度是指包括包頭和數據部分在內的總的字節數。因為包頭的長度是固定的,所以該域主要用來表示數據部分的長度(又稱為數據負載)。

  2.2.1、UDP內部工作原理

  與TCP不同,UDP不會進行流控制。接下來具體討論UDP的作用,如下圖所示:

 

  從上圖可以看出,IP的作用就是讓離開主機B的UDP數據包准備傳遞到主機A。但把UDP包最終交給主機A的某一UDP套接字的過程是由UDP完成的,UDP最重要的作用就是根據端口號將傳到主機的數據包交付給最終的UDP套接字

  2.2.2、UDP的高效使用

  雖然大部分網絡編程都是基於TCP實現的,但也有一些是用UDP實現的。接下來考慮何時實用UDP更有效,其實UDP也具有一定的可靠性,但是網絡傳輸特性導致信息丟失頻發,比如傳遞壓縮文件要發送一萬個數據包,只要丟失一個這個壓縮文件都無法解壓。但通過網絡實時傳輸視頻或音頻時情況就不同了。對於多媒體數據而言,丟失一部分也沒太大問題,只會引起短暫的畫面抖動或出現細微的雜音。但因為需要提供實時服務,速度就成為至關重要的因素。因此,TCP的流控制就顯得有點多余,此時需要考慮的是UDP。

  但UDP並非每次都快於TCP,TCP比UDP慢的原因通常有以下兩點:收發數據前后進行的連接設置及清除過程、收發數據過程中為保證可靠性而添加的流控制。

  如果收發的數據量小但需要頻繁連接時,UDP比TCP更高效。

  2.2.3、UDP中的服務器端和客戶端沒有連接

  UDP服務端/客戶端不像TCP那樣在連接狀態下交換數據,因此與TCP不同,無需經過連接過程。也就是說,不必像TCP連接過程中調用listen和accept函數。UDP中只有創建套接字過程和數據交換過程。

  2.2.4、UDP服務器端和客戶端均只需一個套接字

  TCP中,套接字之間應該是一對一的關系。若要向十個客戶端提供服務,則除了服務端套接字外,還需要十個用於與客戶端連接的套接字,也就是由accept所產生的套接字。但在UDP中,不管是服務器端還是客戶端都只需要一個UDP套接字就可以向任何主機傳輸數據,如下圖UDP套接字通信模型:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  上圖展示了一個UDP套接字與兩個不同主機交換數據的過程,也就是說,只需一個UDP套接字就能和多台主機通信

  2.2.5、UDP客戶端套接字的地址分配

  從UDP的編程流程可以看出UDP缺少把IP端口分配給套接字的過程,TCP客戶端調用connect函數自動完成此過程,而UDP連能承擔相同功能的函數調用語句都沒有,究竟是在何時分配IP地址和端口號呢?

  UDP程序中,調用sendto函數傳輸數據前完成對套接字的地址分配工作,因此調用bind函數。當然,bind函數在TCP程序中出現過,但bind函數不區分TCP和UDP。另外調用sendto函數時尚未分配地址信息,則在首次調用sendto函數時給相應套接字自動分配IP地址和端口。而且此時分配的地址一直保留到程序結束為止。因此也可用來與其他UDP套接字進行數據交換,當然IP用主機IP,端口號選尚未使用的任意端口號。

  綜上所述,調用sendto函數時自動分配IP和端口號,因此UDP客戶端中通常無需額外的地址分配過程。

  2.2.6、基於UDP的數據I/O函數

  創建好TCP套接字后,傳輸數據時無需再添加地址信息,因為TCP套接字將保持與對方套接字的連接。換言之,TCP套接字知道目標地址信息。但UDP套接字不會保持連接狀態(UDP套接字只有簡單的郵筒功能),因此每次傳輸數據都要添加目標地址信息。這相當於寄信前在信件中填寫地址,接下來介紹填寫地址並傳輸數據時調用的UDP相關函數 。  

#include <sys/socket.h>
ssize_t sendto(int sock, const void *buff, size_t nbytes, int flags, const struct sockaddr *to, socklen_t addrlen);//成功時返回傳輸的字節數,失敗時返回-1
  • sock:用於傳輸數據的UDP套接字文件描述符
  • buff:保存待傳輸數據的緩沖地址值
  • nbytes:待傳輸的數據長度,以字節為單位
  • flags:可選項參數,若沒有則傳遞0
  • to:存有目標地址信息的sockaddr結構體變量的地址值
  • addrlen:傳遞給參數to的地址值結構體變量長度

   上述函數與之前的TCP輸出函數最大的區別在於,此函數需要向它傳遞目標地址信息。接下來介紹接收UDP數據的函數,UDP數據的發送端並不固定,因此該函數定義為可接收發送端信息的形式,也就是將同時返回UDP數據包的發送端信息。

#include <sys/socket.h>
ssize_t recvfrom (int sock, void *buff, size_t nbytes, int flags, struct sockaddr * from, socklen_t * addrlen);//成功時返回接收的字節數,失敗時返回-1
  • sock:用於接收數據的UDP套接字文件描述符
  • buff:保存接收數據的緩沖地址值
  • nbytes:可接收的最大字節數,故無法超過參數buff所指的緩沖大小
  • flags:可選項參數,若沒有則傳遞0
  • from:存有發送端地址信息的sockaddr結構體變量的地址值
  • addrlen:保存參數from的結構體變量長度的變量地址值

  編寫UDP程序時最核心的部分就在於上述兩個函數,也說明二者在UDP數據傳輸中的地位。

  2.2.7、UDP的數據傳輸特性

  TCP傳輸的數據不存在數據邊界,而UDP數據傳輸中存在數據邊界。前面說過,TCP數據傳輸中不存在邊界,這表名數據傳輸過程中調用I/O函數的次數不具有任何意義。相反,UDP是具有數據邊界協議的,傳輸中調用I/O函數的次數非常重要。因此,輸入函數的調用次數應和輸出函數的調用次數完全一致,這樣才能保證接收全部已發送的數據。

  2.2.8、已連接(connected)UDP套接字與未連接(unconnected)UDP套接字

  TCP套接字中需注冊待傳輸數據的目標IP和端口號,而UDP中則無需注冊。因此,通過sendto函數傳輸數據的過程大致可分為以下三個階段:

    第一階段:向UDP套接字注冊目標IP和端口號

    第二階段:傳輸數據

    第三階段:傳輸UDP套接字中注冊的目標地址信息

  每次調用sendto函數時重復上述過程,每次都變更目標地址,因此可以重復利用同一UDP套接字向不同目標傳輸數據。這種未注冊目標地址信息的套接字稱為未連接套接字,反之,注冊了目標地址的套接字稱為連接connected套接字。顯然,UDP套接字默認屬於未連接套接字。但是,要與同一主機進行長時間通信時,將UDP套接字變為已連接套接字會提高效率,上述三個階段中,第一個階段和第三個階段將占用整個通信過程的1/3的時間,縮短這部分時間將大大提高性能

  2.3、協議的選擇

  協議的選擇應該烤爐到數據的可靠性、應用的實時性和網絡的可靠性。

  (1)對數據可靠性要求高的應用需選擇TCP,而對數據的可靠性要求不那么高的應用可選擇UDP。

  (2)TCP中的3次握手、重傳確認等手段可以保證數據傳輸的可靠性,但使用TCP會有較大的延時,因此不適合對實時性要求較高的應用,而UDP則有很好的實時性。

  (3)網絡狀況不是很好的情況下需選用TCP(如在廣域網),網絡狀況很好的情況下選擇UDP可以減少網絡負荷。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM