TCP如何區分監聽套接字和已連接套接字

轉:http://book.51cto.com/art/201005/203019.htm

2.10 TCP端口號與併發服務器

併發服務器中主服務器循環通過派生一個子進程來處理每個新的連接。如果一個子進程繼續使用服務器衆所周知的端口來服務一個長時間的請求,那將發生什麼?讓我們來看一個典型的序列。首先,在主機freebsd上啓動服務器,該主機是多宿的,其IP地址爲12.106.32.254和192.168.42.1。服務器在它的衆所周知的端口(本例爲21)上執行被動打開,從而開始等待客戶的請求,如圖2-11所示。

 
圖2-11 TCP服務器在端口21上執行被動打開

我們使用記號{*:21, *:*}指出服務器的套接字對。服務器在任意本地接口(第一個星號)的端口21上等待連接請求。外地IP地址和外地端口都沒有指定,我們用"*.*"來表示。我們稱它爲監聽套接字(listening socket)。

我們用分號來分割IP地址和端口號,因爲這是HTTP的用法,其他地方也常見。netstat程序使用點號來分割IP地址和端口號,不過如此表示有時候會讓人混淆,因爲點號既用於域名(如freebsd.unpbook.com.21),也用於IPv4的點分十進制數記法(如12.106.32. 254.21)。

這裏指定本地IP地址的星號稱爲通配(wildcard)符。如果運行服務器的主機是多宿的(如本例),服務器可以指定它只接受到達某個特定本地接口的外來連接。這裏要麼選一個接口要麼選任意接口。服務器不能指定一個包含多個地址的清單。通配的本地地址表示"任意"這個選擇。在圖1-9中,通配地址通過在調用bind之前把套接字地址結構中的IP地址字段設置成INADDR_ANY來指定。

稍後在IP地址爲206.168.112.219的主機上啓動第一個客戶,它對服務器的IP地址之一12.106.32.254執行主動打開。我們假設本例中客戶主機的TCP爲此選擇的臨時端口爲1500,如圖2-12所示。圖中在該客戶的下方標出了它的套接字對。

 
(點擊查看大圖)圖2-12 客戶對服務器的連接請求

當服務器接收並接受這個客戶的連接時,它fork一個自身的副本,讓子進程來處理該客戶的請求,如圖2-13所示。(我們將在4.7節中講解fork函數。)

至此,我們必須在服務器主機上區分監聽套接字和已連接套接字(connected socket)。注意已連接套接字使用與監聽套接字相同的本地端口(21)。還要注意在多宿服務器主機上,連接一旦建立,已連接套接字的本地地址(12.106.32.254)隨即填入。

 
(點擊查看大圖)圖2-13 併發服務器讓子進程處理客戶

下一步我們假設在客戶主機上另有一個客戶請求連接到同一個服務器。客戶主機的TCP爲這個新客戶的套接字分配一個未使用的臨時端口,譬如說1501,如圖2-14所示。服務器上這兩個連接是有區別的:第一個連接的套接字對和第二個連接的套接字對不一樣,因爲客戶的TCP給第二個連接選擇了一個未使用的端口(1501)。

 
(點擊查看大圖)圖2-14 第二個客戶與同一個服務器的連接

通過本例應注意,TCP無法僅僅通過查看目的端口號來分離外來的分節到不同的端點。它必須查看套接字對的所有4個元素才能確定由哪個端點接收某個到達的分節。圖2-14中對於同一個本地端口(21)存在3個套接字。如果一個分節來自206.168.112.219端口1500,目的地爲12.106.32.254端口21,它就被遞送給第一個子進程。如果一個分節來自206.168.112.219端口1501,目的地爲12.106.32.254端口21,它就被遞送給第二個子進程。所有目的端口爲21的其他TCP分節都被遞送給擁有監聽套接字的最初那個服務器(父進程)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章