accept產生的Socket端口是多少?

要寫網絡程序就必須用Socket,這是程序員都知道的。而且,面試的時候,我們也會問對方會不會Socket編程?一般來說,很多人都會說,Socket編程基本就是listenaccept以及sendwrite等幾個基本的操作。是的,就跟常見的文件操作一樣,只要寫過就一定知道。

對於網絡編程,我們也言必稱TCP/IP,似乎其它網絡協議已經不存在了。對於TCP/IP,我們還知道TCPUDP,前者可以保證數據的正確和可靠性,後者則允許數據丟失。最後,我們還知道,在建立連接前,必須知道對方的IP地址和端口號。除此,普通的程序員就不會知道太多了,很多時候這些知識已經夠用了。最多,寫服務程序的時候,會使用多線程來處理併發訪問。

我們還知道如下幾個事實:

1。一個指定的端口號不能被多個程序共用。比如,如果IIS佔用了80端口,那麼Apache就不能也用80端口了。

2。很多防火牆只允許特定目標端口的數據包通過。

3。服務程序在listen某個端口並accept某個連接請求後,會生成一個新的socket來對該請求進行處理。

於是,一個困惑了我很久的問題就產生了。如果一個socket創建後並與80端口綁定後,是否就意味着該socket佔用了80端口呢?如果是這樣的,那麼當其accept一個請求後,生成的新的socket到底使用的是什麼端口呢(我一直以爲系統會默認給其分配一個空閒的端口號)?如果是一個空閒的端口,那一定不是80端口了,於是以後的TCP數據包的目標端口就不是80--防火牆一定會組織其通過的!實際上,我們可以看到,防火牆並沒有阻止這樣的連接,而且這是最常見的連接請求和處理方式。我的不解就是,爲什麼防火牆沒有阻止這樣的連接?它是如何判定那條連接是因爲connet80端口而生成的?是不是TCP數據包裏有什麼特別的標誌?或者防火牆記住了什麼東西?

後來,我又仔細研讀了TCP/IP的協議棧的原理,對很多概念有了更深刻的認識。比如,在TCPUDP同屬於傳輸層,共同架設在IP層(網絡層)之上。而IP層主要負責的是在節點之間(End to End)的數據包傳送,這裏的節點是一臺網絡設備,比如計算機。因爲IP層只負責把數據送到節點,而不能區分上面的不同應用,所以TCPUDP協議在其基礎上加入了端口的信息,端口於是標識的是一個節點上的一個應用。除了增加端口信息,UPD協議基本就沒有對IP層的數據進行任何的處理了。而TCP協議還加入了更加複雜的傳輸控制,比如滑動的數據發送窗口(Slice Window),以及接收確認和重發機制,以達到數據的可靠傳送。不管應用層看到的是怎樣一個穩定的TCP數據流,下面傳送的都是一個個的IP數據包,需要由TCP協議來進行數據重組。

所以,我有理由懷疑,防火牆並沒有足夠的信息判斷TCP數據包的更多信息,除了IP地址和端口號。而且,我們也看到,所謂的端口,是爲了區分不同的應用的,以在不同的IP包來到的時候能夠正確轉發。

TCP/IP只是一個協議棧,就像操作系統的運行機制一樣,必須要具體實現,同時還要提供對外的操作接口。就像操作系統會提供標準的編程接口,比如Win32編程接口一樣,TCP/IP也必須對外提供編程接口,這就是Socket編程接口--原來是這麼回事啊!

Socket編程接口裏,設計者提出了一個很重要的概念,那就是socket。這個socket跟文件句柄很相似,實際上在BSD系統裏就是跟文件句柄一樣存放在一樣的進程句柄表裏。這個socket其實是一個序號,表示其在句柄表中的位置。這一點,我們已經見過很多了,比如文件句柄,窗口句柄等等。這些句柄,其實是代表了系統中的某些特定的對象,用於在各種函數中作爲參數傳入,以對特定的對象進行操作--這其實是C語言的問題,在C++語言裏,這個句柄其實就是this指針,實際就是對象指針啦。

現在我們知道,socketTCP/IP並沒有必然的聯繫。Socket編程接口在設計的時候,就希望也能適應其他的網絡協議。所以,socket的出現只是可以更方便的使用TCP/IP協議棧而已,其對TCP/IP進行了抽象,形成了幾個最基本的函數接口。比如createlistenacceptconnectreadwrite等等。

現在我們明白,如果一個程序創建了一個socket,並讓其監聽80端口,其實是向TCP/IP協議棧聲明瞭其對80端口的佔有。以後,所有目標是80端口的TCP數據包都會轉發給該程序(這裏的程序,因爲使用的是Socket編程接口,所以首先由Socket層來處理)。所謂accept函數,其實抽象的是TCP的連接建立過程。accept函數返回的新socket其實指代的是本次創建的連接,而一個連接是包括兩部分信息的,一個是源IP和源端口,另一個是宿IP和宿端口。所以,accept可以產生多個不同的socket,而這些socket裏包含的宿IP和宿端口是不變的,變化的只是源IP和源端口。這樣的話,這些socket宿端口就可以都是80,而Socket層還是能根據源/宿對來準確地分辨出IP包和socket的歸屬關係,從而完成對TCP/IP協議的操作封裝!而同時,放火牆的對IP包的處理規則也是清晰明瞭,不存在前面設想的種種

複雜的情形。

明白socket只是對TCP/IP協議棧操作的抽象,而不是簡單的映射關係,這很重要!

 

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