---------------------------------------------------------------
1、什麼是多路複用和多路分解
咱們知道,在網絡上主機與主機之間的通訊,實質上是主機上運行的應用進程之間的通訊。例如,當你經過Http上網瀏覽網頁時,實質上是你所訪問的主機的服務器進程與你本機的瀏覽器進程在進行通訊。試想一下,當你在上網的同時,還掛着QQ,還使用ftp下載大文件,這時就有三個網絡上的進程與你的主機上的三個進程進行通訊,那麼系統是怎麼樣正確地把接收到的數據定位到指定的進程中的呢?也就是說,系統是怎麼把從ftp服務器發送過來的數據交付到ftp客戶端,而不把這些數據交付到你的QQ上的呢?反過來考慮,系統又是如何精確地把來自各個應用進程的數據發到網絡上指定上的主機(服務器)上的對應進程的呢?這就是多路分解與多路複用的做用了。
爲了說明這個問題,先來補充一下操做系統方面的知識,以Linux對文件和設備的管理和使用方式爲例。
爲了方便資源的使用,提升機器的性能、利用率和穩定性等等緣由,咱們的計算機都有一層軟件叫作操做系統,它用於幫咱們管理計算機可使用的資源,當咱們的程序要使用一個資源的時候,能夠向操做系統申請,再由操做系統爲咱們的程序分配和管理資源。一般當咱們要訪問一個內核設備或文件時,程序能夠調用系統函數,系統就會爲咱們打開設備或文件,而後返回一個文件描述符fd(或稱爲ID,是一個整數),咱們要訪問該設備或文件,只能經過該文件描述符。能夠認爲該編號對應着打開的文件或設備。
而當咱們的程序要使用網絡時,要使用到對應的操做系統內核的操做和網卡設備,因此咱們能夠向操做系統申請,而後系統會爲咱們建立一個套接字Socket,並返回這個Socket的ID,之後咱們的程序要使用網絡資源,只要向這個Socket的編號ID操做便可。而咱們的每個網絡通訊的進程至少對應着一個Socket。向Socket的ID中寫數據,至關於向網絡發送數據,向Socket中讀數據,至關於接收數據。並且這些套接字都有惟一標識符——端口號。
有了上面的瞭解後,再來講說什麼是多路分解和多路複用。
每一個運輸層的報文段中設置了幾個字段,包括源端口號和目的端口號等。多路分解就是,在接收端,運輸層檢查這些字段並標識出接收套接字,而後將該報文定向到該套接字。其工做方式能夠簡單地認爲是這樣的,主機上的每一個每一個套接字被分配一個端口號,當報文到達主機時,運輸層檢查報文段中的目的端口號,並將其定向到相應的套接字。
多路複用就是從源主機的不一樣套接字中收集數據塊,併爲每一個數據塊封裝上首部信息從而生成報文段,而後將報文段傳遞到網絡層中去。
2、無鏈接的多路複用和多路分解
在運輸層,無鏈接的網絡傳輸是經過UDP來實現的。UDP報文中只有源端口號和目的端口號,一個UDP套接字是由一個含有目的IP地址和目的端口號的二元組來全面標識的。在客戶端,源端口號是客戶進程套接字的端口號,目的端口號是服務器的端口號。而在服務器端,源端口號是服務器的建立的套接字的端口號,而目的端口號是客戶端的套接字的端口號。
例如主機A產生了一個UDP報文段,報文段中就會包括源端口號(11111)、目的端口號(22222)、程序數據(還有兩個其餘的值,在這裏咱們不關心)。而後,運輸層將生成的報文段交給網絡層。網絡層將其放到一個IP數據報中,並提供盡力而爲的交付,將其發送到主機B中。若是該報文到達主機B,主機B運輸層就會檢查該報文的端口號,並將該報文段傳遞給套接字的端口號爲接收到的報文段的目的端口號(22222)的套接字。從而實現了進程間的網絡通訊。而源端口號的做用是爲了讓主機B能向主機A發送信息的,也就是說,當主機B在接收到主機A的數據後,要向主機A發送一個迴應時,主機B發送的報文段的目的端口號就是11111.
注意:咱們看到使用UDP來傳輸報文段時,一個UDP套接字是由一個含有目的IP地址和目的端口號的二元組來全面標識的。所以,若是兩個UDP報文段有不一樣的源IP地址和源端口,但具備相同的IP地址和目的端口號,那麼這兩個報文段將經過相同的目的端口號定向到相同的目的進程。這裏沒有過多地說明IP地址,是由於IP地址是網絡層的知識,因此沒有說起,咱們如今只須知道,IP地址對應着一臺主機,而端口號對應着一臺主機上的一個進程(或套接字)。
3、面向鏈接的多路複用和多路分解
從上面的解說中,咱們能夠知道,網絡上主機間的進程間通訊,實質上是經過套接字來實現的。在運輸層中面向鏈接的網絡傳輸多使用TCP,而TCP套接字和UDP套接字之間有一個細微的差異,就是,TCP套接字是由一個四元組(源IP地址、源端口號,目的IP地址,目的端口號)來標識的。這樣,當一個TCP報文段從網絡到達一臺主機時,主機會使用所有4個值來將報文段定向,即多路分解到相應的套接字。
與UDP不一樣的是,兩個具備不一樣源IP或源端口號的到達的TCP報文段將被重定向到兩個不一樣的套接字。
儘管如此,而TCP的多路利用和多路分解的工做原理與無鏈接的UDP的多路複用和多路分解的原理仍是大體同樣的。
想一想爲何TCP的多路複用和多路分解要這樣設計呢?我的認爲,這是由於TCP和UDP對待接收到的數據的處理方式不一樣所致的。咱們以服務器上的TCP套接字和UDP套接字爲例,假定服務器接收客戶端的數據,並把數據發送回客戶端。
當一個UDP服務器接收到一個UDP報文段時,它會根據收到的UDP報文段的源IP和源端口號,把數據發送回客戶端,它並不須要建立一個新的套接字來處理該報文段;
而對於一個TCP服務器,當它接受一個鏈接時,它會產生一個新的套接字,而後經過新的套接字來與客戶端通訊,也就是經過新的套接字來把數據發送回給客戶端。因爲每個鏈接都會產生一個新的套接字,因此具備不一樣的源IP或源端口號的鏈接就是一個不一樣的鏈接,對應着產生的新的不一樣的套接字。
試想一下,若是TCP套接字也是使用像UDP那樣的只用源端口號和目的端口號來徹底標識一個套接字,那麼當客戶機A有一個Http鏈接時,該TCP報文的目的端口號爲80,目的IP地址爲TCP服務的IP地址。TCP服務器產生一個新的套接字來處理該請求,此時,客戶機B又有一個Http鏈接,TCP報文的目的端口號也爲80,目的IP地址也爲TCP服務的IP地址。而TCP套接字也是使用像UDP那樣,兩個具備不一樣的源Ip或源端口號但具備相同目的IP和目的端口的報文段定位到同一個套接字中,那麼這個客戶機B的TCP報文段則會多路分解到客戶機A的套接字上,而該套接字並不該該被客戶機B的Http鏈接使用。
PS:若是對於這個解說不太明白,能夠看看本人寫的一個用TCP和UDP進行通訊的小例子,