您好,登錄后才能下訂單哦!
對于網絡編程,我們也言必稱 TCP/IP ,似乎其它網絡協議已經不存在了。對于 TCP/IP ,我們還知道 TCP 和 UDP ,前者可以保證數據的正確和可靠性,后者則允許數據丟失。最后,我們還知道,在建立連接前,必須知道對方的 IP 地址和端口號。除此,普通的程序員就不會知道太多了,很多時候這些知識已經夠用了。最多,寫服務程序的時候,會使用多線程來處理并發訪問。
我們還知道如下幾個事實:
1 。一個指定的端口號不能被多個程序共用。比如,如果 IIS 占用了 80 端口,那么 Apache 就不能也用 80 端口了。
2 。很多防火墻只允許特定目標端口的數據包通過。
3 。服務程序在 listen 某個端口并 accept 某個連接請求后,會生成一個新的 socket 來對該請求進行處理。
于是,一個困惑了我很久的問題就產生了。如果一個 socket 創建后并與 80 端口綁定后,是否就意味著該 socket 占用了 80 端口呢?如果是這樣的,那么當其 accept 一個請求后,生成的新的 socket 到底使用的是什么端口呢(我一直以為系統會默認給其分配一個空閑的端口號)?如果是一個空閑的端口,那一定不是 80 端口了,于是以后的 TCP 數據包的目標端口就不是 80 了 -- 防火墻一定會組織其通過的!實際上,我們可以看到,防火墻并沒有阻止這樣的連接,而且這是最常見的連接請求和處理方式。我的不解就是,為什么防火墻沒有阻止這樣的連接?它是如何判定那條連接是因為 connet80 端口而生成的?是不是 TCP 數據包里有什么特別的標志?或者防火墻記住了什么東西?
后來,我又仔細研讀了 TCP/IP 的協議棧的原理,對很多概念有了更深刻的認識。比如,在 TCP 和 UDP 同屬于傳輸層,共同架設在 IP 層(網絡層)之上。而 IP 層主要負責的是在節點之間( End to End )的數據包傳送,這里的節點是一臺網絡設備,比如計算機。因為 IP 層只負責把數據送到節點,而不能區分上面的不同應用,所以 TCP 和 UDP 協議在其基礎上加入了端口的信息,端口于是標識的是一個節點上的一個應用。除了增加端口信息, 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 指針,實際就是對象指針啦。
現在我們知道, socket 跟 TCP/IP 并沒有必然的聯系。 Socket 編程接口在設計的時候,就希望也能適應其他的網絡協議。所以, socket 的出現只是可以更方便的使用 TCP/IP 協議棧而已,其對 TCP/IP 進行了抽象,形成了幾個最基本的函數接口。比如 create , listen , accept , connect , read 和 write 等等。
現在我們明白,如果一個程序創建了一個 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 協議棧操作的抽象,而不是簡單的映射關系,這很重要!
一個socket 由四個標識決定,客戶端ip,客戶端port, 服務端ip,服務端port,
在一個客戶端和服務端通信過程中,客戶端ip, 服務端ip,服務端port,都是相同的,只有客戶端port不同,但是只要一個不同,就算是一個新的socket,
所以accept 返回的是一個新的socket。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。