C語言中文網 目錄
首頁 > socket 閱讀:2,703

面向連接和無連接的套接字到底有什么區別?

上一節《套接字有哪些類型》提到,流格式套接字(Stream Sockets)就是“面向連接的套接字”,它基于 TCP 協議;數據報格式套接字(Datagram Sockets)就是“無連接的套接字”,它基于 UDP 協議。

這給大家造成一種印象,面向連接就是可靠的通信,無連接就是不可靠的通信,實際情況是這樣嗎?

另外,不管是哪種數據傳輸方式,都得通過整個 Internet 網絡的物理線路將數據傳輸過去,從這個層面理解,所有的 socket 都是有物理連接的呀,為什么還有無連接的 socket 呢?

本節就來給大家解開種種謎團,加深大家對數據傳輸方式的認識。

從字面上理解,面向連接好像有一條管道,它連接發送端和接收端,數據包都通過這條管道來傳輸。當然,兩臺計算機在通信之前必須先搭建好管道。

無連接好像沒頭蒼蠅亂撞,數據包從發送端到接收端并沒有固定的線路,愛怎么走就怎么走,只要能到達就行。每個數據包都比較自私,不和別人分享自己的線路,但是,大家最終都能殊途同歸,到達接收端。

這樣理解沒錯,但是我相信這還不夠深入,大家還是感覺云里霧里,沒有看到本質。好,接下來就是見證奇跡的時刻,我會用實例給大家演示!

一個簡化的互聯網模型

上圖是一個簡化的互聯網模型,H1 ~ H6 表示計算機,A~E 表示路由器,發送端發送的數據必須經過路由器的轉發才能到達接收端。

假設 H1 要發送若干個數據包給 H6,那么有多條路徑可以選擇,比如:
  • 路徑①:H1 --> A --> C --> E --> H6
  • 路徑②:H1 --> A --> B --> E --> H6
  • 路徑③:H1 --> A --> B --> D --> E --> H6
  • 路徑④:H1 --> A --> B --> C --> E --> H6
  • 路徑⑤:H1 --> A --> C --> B --> D --> E --> H6
數據包的傳輸路徑是路由器根據算法來計算出來的,算法會考慮很多因素,比如網絡的擁堵狀況、下一個路由器是否忙碌等。

無連接的套接字

對于無連接的套接字,每個數據包可以選擇不同的路徑,比如第一個數據包選擇路徑④,第二個數據包選擇路徑①,第三個數據包選擇路徑②……當然,它們也可以選擇相同的路徑,那也只不過是巧合而已。

每個數據包之間都是獨立的,各走各的路,誰也不影響誰,除了迷路的或者發生意外的數據包,最后都能到達 H6。但是,到達的順序是不確定的,比如:
  • 第一個數據包選擇了一條比較長的路徑(比如路徑⑤),第三個數據包選擇了一條比較短的路徑(比如路徑①),雖然第一個數據包很早就出發了,但是走的路比較遠,最終還是晚于第三個數據包達到。
  • 第一個數據包選擇了一條比較短的路徑(比如路徑①),第三個數據包選擇了一條比較長的路徑(比如路徑⑤),按理說第一個數據包應該先到達,但是非常不幸,第一個數據包走的路比較擁堵,這條路上的數據量非常大,路由器處理得很慢,所以它還是晚于第三個數據包達到了。

還有一些意外情況會發生,比如:
  • 第一個數據包選擇了路徑①,但是路由器C突然斷電了,那它就到不了 H6 了。
  • 第三個數據包選擇了路徑②,雖然路不遠,但是太擁堵,以至于它等待的時間太長,路由器把它丟棄了。

總之,對于無連接的套接字,數據包在傳輸過程中會發生各種不測,也會發生各種奇跡。H1 只負責把數據包發出,至于它什么時候到達,先到達還是后到達,有沒有成功到達,H1 都不管了;H6 也沒有選擇的權利,只能被動接收,收到什么算什么,愛用不用。

無連接套接字遵循的是「盡最大努力交付」的原則,就是盡力而為,實在做不到了也沒辦法。無連接套接字提供的沒有質量保證的服務。

面向連接的套接字

面向連接的套接字在正式通信之前要先確定一條路徑,沒有特殊情況的話,以后就固定地使用這條路徑來傳遞數據包了。當然,路徑被破壞的話,比如某個路由器斷電了,那么會重新建立路徑。

選好的路徑

這條路徑是由路由器維護的,路徑上的所有路由器都要存儲該路徑的信息(實際上只需要存儲上游和下游的兩個路由器的位置就行),所以路由器是有開銷的。

H1 和 H6 通信完畢后,要斷開連接,銷毀路徑,這個時候路由器也會把之前存儲的路徑信息擦除。

在很多網絡通信教程中,這條預先建立好的路徑被稱為“虛電路”,就是一條虛擬的通信電路。

為了保證數據包準確、順序地到達,發送端在發送數據包以后,必須得到接收端的確認才發送下一個數據包;如果數據包發出去了,一段時間以后仍然沒有得到接收端的回應,那么發送端會重新再發送一次,直到得到接收端的回應。這樣一來,發送端發送的所有數據包都能到達接收端,并且是按照順序到達的。
發送端發送一個數據包,如何得到接收端的確認呢?很簡單,為每一個數據包分配一個 ID,接收端接收到數據包以后,再給發送端返回一個數據包,告訴發送端我接收到了 ID 為 xxx 的數據包。
面向連接的套接字會比無連接的套接字多出很多數據包,因為發送端每發送一個數據包,接收端就會返回一個數據包。此外,建立連接和斷開連接的過程也會傳遞很多數據包。

不但是數量多了,每個數據包也變大了:除了源端口和目的端口,面向連接的套接字還包括序號、確認信號、數據偏移、控制標志(通常說的 URG、ACK、PSH、RST、SYN、FIN)、窗口、校驗和、緊急指針、選項等信息;而無連接的套接字則只包含長度和校驗和信息。

有連接的數據包比無連接大很多,這意味著更大的負載和更大的帶寬。許多即時聊天軟件采用 UDP 協議(無連接套接字),與此有莫大的關系。

總結

兩種套接字各有優缺點:
  • 無連接套接字傳輸效率高,但是不可靠,有丟失數據包、搗亂數據的風險;
  • 有連接套接字非常可靠,萬無一失,但是傳輸效率低,耗費資源多。


兩種套接字的特點決定了它們的應用場景,有些服務對可靠性要求比較高,必須數據包能夠完整無誤地送達,那就得選擇有連接的套接字(TCP 服務),比如 HTTP、FTP 等;而另一些服務,并不需要那么高的可靠性,效率和實時才是它們所關心的,那就可以選擇無連接的套接字(UDP 服務),比如 DNS、即時聊天工具等。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo