socket accept後的fd是否佔用新端口

今天小組討論了下自動化部署的架構與實現。在討論推送配置的時候,我發現了一個問題,這也讓我知道了我以前一直忽略的一個東西。


很多人socket編程很熟悉,但是能知道下面細節的人就不是那麼多了。以前就想讀tcp ip協議詳解,可惜那時候的功力還沒到,看來等有時間還是得細細品讀。


大家都很熟悉,在server端編程,首先得創建一個socket並bind一個地址,然後進行listen和accept,當客戶端有連接的時候,accept會返回一個fd,代表了與客戶端的連接,我們可以通過這個fd來跟對應的client端進行io通訊,也可以捕捉到斷開的事件。


問題就在上面accept的fd上面。我以前的理解一直以爲這個fd佔用了一個新的端口號,並且這個佔用的端口號與client一致,通過相同的端口號進行傳輸。當時也沒有懷疑正確與否,現在想來,真是錯誤百出。


首先,socketlisten後,是肯定佔用了對應的端口號的,任何別的嘗試使用該端口的操作肯定會報錯,這是毋庸置疑的。accept的新的fd,佔不佔用新的端口號呢?看到這裏大家肯定也都明白了,是不佔用的。那不佔用,肯定和listen的端口一樣啊?不是上面說了一個端口只能使用一次嗎?


這裏就引出了socket的底層結構。區別兩個socket是否一致,需要5元組來區別,分別是本機的ip 本機的端口 目標機的ip 目標機的端口 還有一個是協議。通過這些可以唯一的區別socket,當這些一致,那麼這兩個socket是一樣的。系統提供的api,比如bind listen connect,其實都隱藏了對socket元組信息的寫入。


再談談上述的問題,在accept一個新的連接後,其實fd的確是新的fd,但是它的本機ip port是和listen的一樣的,而不同的client的fd之間的區別,就是不同的目標機的ip port信息。


這個問題解決了,那麼我們再梳理一下結構。爲何系統要劃分端口號?其實端口這個概念,是在tcp這一層,即傳輸層實現的東西,爲上層應用層提供支持。當應用層通過socket send數據的時候,tcp層會根據目標主機的ip port等信息進行數據包的進一步封裝,然後將其交給ip層來進行網絡傳輸,ip層則根據目標ip地址來將其再次封裝然後最終交給物理層進行傳輸。

而對於client來說,首先ip層會收到這個數據,然後根據頭部信息中的協議來交給不同的協議來進行處理。向上交給tcp層之後,tcp層會從頭部數據中獲取到端口號信息,到這一步其實已經可以唯一確定是哪個進程的數據了,通過端口號查到進程,並通知進程進行處理。這樣整個通訊就走通了。


上面也談到了,每一個socket都有一個local address和remote address,而對應的遠程client的socket,也有一個local address和remote address,有意思的是,他們是互相相反的關係。其實想想也是,tcp向下傳輸的時候,需要給ip層傳入remote ip,用於路由傳輸,而remote port,則會附加到數據頭部中,因爲這個remote port是需要給client來區分進程的。client收到了這個數據包後,根據server傳入的port,則可以唯一的區分是哪個進程的數據包。而client發送的數據,則會帶入client這個socket的remote port,然後最終數據會傳輸給server listen 的那個socket。tcp數據頭中還會有client的local address的信息,所以發送到server監聽的socket上後,可以通過client的ip port來區分是哪一個client發送的數據,之後的就交由應用程序來處理了。


上面的總結也就是每個socket都是有着通過local address來與remote address相連的意思,也就是兩個端口號是可以不一樣的。


當然上面的只是記錄下今天的想法,只是感覺有必要去讀下tcp ip協議了,以前讀着摸不着頭腦,現在讀着卻有着原來是這樣啊的感慨。

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