我們電腦上的數據,是如何“走”到遠端的另一臺電腦的呢?這是個最基礎的問題,可能很多人回答不上來,盡管我們每天都在使用網絡。這里我們以一個最簡單的“ping”命令,來解釋一個數據包“旅程”。
假設:我的電腦A,向遠在外地的朋友電腦B傳輸數據,最簡單的就是“ping”一下,看看這個家伙的那一端網絡通不通。A與B之間只有一臺路由器。(路由器可能放在學校,社區或者電信機房,無所謂,基本原理是一樣的)
具體過程如下------
1.“ping”命令所產生的數據包,我們歸類為ICMP協議。說白了就是向目的地發送一個數據包,然后等待回應,如果回應正常則目的地的網絡就是通的。當我們輸入了“ping”命令之后,我們的機器(電腦A)就生成了一個包含ICMP協議域的數據包,姑且稱之為“小德”吧~~~~
2.“小德”已經將ICMP協議打包到數據段里了,可是還不能發送,因為一個數據要想向外面傳送,還得經過“有關部門”的批準------IP協議。IP要將你的“寫信人地址”和“收信人地址”寫到數據段上面,即:將數據的源IP地址和目的IP地址分別打包在“小德”的頭部和尾部,這樣一來,大家才知道你的數據是要送到哪里。
3.準備工作還沒有完。接下來還有部門要審核------ARP。ARP屬于數據鏈路層協議,主要負責把IP地址對應到硬件地址。直接說吧,都怪交換機太“傻”,不能根據IP地址直接找到相應的計算機,只能根據硬件地址來找。于是,交換機就經常保留一張IP地址與硬件地址的對應表以便其查找目的地。而ARP就是用來生成這張表的。比如:當“小德”被送到ARP手里之后,ARP就要在表里面查找,看看“小德”的IP地址與交換機的哪個端口對應,然后轉發過去。如果沒找到,則發一個廣播給所有其他的交換機端口,問這是誰的IP地址,如果有人回答,就轉發給它。
4.經過一番折騰,“小德”終于要走出這個倒霉的局域網了。可在此之前,它們還沒忘給“小德”屁股后面蓋個“戳”,說是什么CRC校驗值,怕“小德”在旅行途中缺胳膊少腿,還得麻煩它們重新發送。。。。。我靠~~~~注:很多人弄不清FCS和CRC。所謂的CRC是一種校驗方法,用來確保數據在傳輸過程中不會丟包,損壞等等,FCS是數據包(準確的說是frame)里的一個區域,用來存放CRC的計算結果的。到了目的地之后,目的計算機要檢查FCS里的CRC值,如果與原來的相同,則說明數據在途中沒有損壞。
5.在走出去之前,那些家伙最后折磨了一次“小德”------把小德身上眾多的0和1,弄成了什么“高電壓”“低電壓”,在雙絞線上傳送了出去。暈~~出趟門就這么麻煩嗎?
6.坐著雙絞線旅游,爽!可當看到很多人坐著同軸電纜,還有坐光纖的時候,小德又感覺不是那么爽了。就在這時,來到了旅途的中轉站------路由器。這地方可是高級場所,人家直接查看IP地址!剩下的一概不管,交給下面的人去做。夠牛吧?路由器的內部也有一張表,叫做路由表,里面標識著哪一個網絡的IP對應著路由器的哪一個端口。這個表也不是天生就有的,而是靠路由器之間互相“學習”之后生成的,當然也可以由管理員手工設定。這個“學習”的過程是依靠路由協議來完成的,比如RIP,EIGRP,OSPF等等。
7.當路由器查看了“小德”的IP地址以后,根據路由表知道了小德要去的網絡,接著就把小德轉到了相應的端口了。至此,路由器的主要工作完成,下面又是打包,封裝成frame,轉換成電壓信號等一系列“折騰”的活,就由數據鏈路層和物理層的模塊去干吧。
8.小德從路由器的出口出來,便來到了目的地----電腦B----所屬的網絡的默認網關。默認網關可以是路由器的一個端口,也可以是局域網里的各種服務器。不管怎樣,下面的過程還是一樣的:到交換機里的ARP表查詢“小德”的IP地址,看看屬于哪個局域網段或端口,然后就轉發到B了。
9.進了B的網卡之后,還要層層“剝皮”,基本上和從A出來的程序是一樣的------電腦B先校驗一下CRC值,看看數據是否完整;然后檢查一下frame的封裝,看到是IP協議之后,就把“小德”交給IP“部門”了;IP協議一看目的地址,正確,再看看應用協議,是ICMP。于是知道了該怎么做了------產生一個回應數據包,(可以命名為“回應小德”),并準備以同樣的順序向遠端的A發送。。至于剛剛收到的那個數據包就丟棄了。
10.“回應小德”這個數據包又開始了上述同樣的循環,只不過這次發送者是B而接收者是A了。
以上是一個最簡單的路由過程,任何復雜的網絡都是在次基礎之上實現的。
網絡數據包大小
用UDP協議發送時,用sendto函數最大能發送數據的長度為:65535-20-8=65507字節,其中20字節為IP包頭長度,8字節為UDP包頭長度。用sendto函數發送數據時,如果指的的數據長度大于該值,則函數會返回錯誤。
用TCP協議發送時,由于TCP是數據流協議,因此不存在包大小的限制(暫不考慮緩沖區的大小),這是指在用send函數時,數據長度參數不受限制。而實際上,所指定的這段數據并不一定會一次性發送出去,如果這段數據比較長,可能會被分段發送,如果比較短,可能會等待和下一次數據一起發送。我在測試的時候,發現長度一般會被切成16384(16K)或49152(48K),不知道這兩個值有什么意義。
轉載地址: