作為兩個最有名的開源操作系統(tǒng),Linux和FreeBSD是網(wǎng)管們的首選。Linux以開放性和眾多的驅(qū)動支持著稱,而FreeBSD有著優(yōu)良的UNIX傳統(tǒng),是公認的最穩(wěn)定的操作系統(tǒng)。那么,在這兩個操作系統(tǒng)間,該如何選擇呢?幸好,我們有源碼,可以從協(xié)議棧的實現(xiàn)中尋找答案。如果效率為先,則Linux當(dāng)為首推,如果穩(wěn)定至上,F(xiàn)reeBSD應(yīng)該為不二之選。 TCP/IP協(xié)議棧是網(wǎng)絡(luò)中廣泛使用的事實網(wǎng)絡(luò)通信標(biāo)準(zhǔn)。最初的TCP實現(xiàn)源自4.4BSDlite,在Linux興起后,也不可避免得支持它。但Linux的實現(xiàn)自成體系,僅與傳統(tǒng)實現(xiàn)保持接口上的兼容,下面我們將針對源碼級的實現(xiàn),來分析一下兩者的異同。但是,對于Linux和FreeBSD這樣優(yōu)秀的系統(tǒng)來說,已經(jīng)無所謂何優(yōu)何劣,有的僅僅是實現(xiàn)策略與側(cè)重點上的不同而已。 從進程的角度上講,可以調(diào)用send,sendto,sendmsg來發(fā)送一段數(shù)據(jù),來可以使用文件系統(tǒng)中的write和writev來發(fā)送數(shù)據(jù)。同理,接收數(shù)據(jù)可以使用相應(yīng)的recv,recvmsg,recvfrom,也可以使用文件系統(tǒng)提供的read,readv來接收一段數(shù)據(jù)。對于接收來說,這是異步進行的,也就是說,這是中斷驅(qū)動的,在以后的分析中,我們要注意這點。為簡單起見,同時不失一般性,我們將分析TCP協(xié)議的輸入輸出全過程,并以已對LINUX及FreeBSD的實現(xiàn)作一對比。 首先我們來看FreeBSD上的協(xié)議實現(xiàn),這也是最正統(tǒng)的實現(xiàn)。下面是完整的輸入輸出路徑。
首先來看左邊的輸出,不管應(yīng)用程序調(diào)用哪個輸出函數(shù),最終都要調(diào)用sosend來完成輸出。Sosend將從用戶空間把數(shù)據(jù)復(fù)制進內(nèi)核管理的m_buf數(shù)據(jù)結(jié)構(gòu),m_buf是FreeBSD的TCP實現(xiàn)使用的數(shù)據(jù)緩沖結(jié)構(gòu)。在sosend完成數(shù)據(jù)復(fù)制后,將調(diào)用TCP的輸出函數(shù),tcp_output要做的事情是分配一個新的m_buf來保存tcp頭,并計算相應(yīng)的數(shù)據(jù)校驗碼,在下一步的ip_output中,同樣也要進行數(shù)據(jù)校驗工作,并進行數(shù)據(jù)路由選擇。最終ether_output將通過if_start來調(diào)用具體的硬件驅(qū)動程序來完成數(shù)據(jù)發(fā)送。在某個網(wǎng)卡的驅(qū)動中,ex_start將負責(zé)將數(shù)據(jù)從內(nèi)核的m_buf緩沖復(fù)制進硬件自己的緩沖區(qū),以完成數(shù)據(jù)發(fā)送工作。在這整個過程中,數(shù)據(jù)被復(fù)制兩次,并且也被遍歷兩次(計算校驗碼),這也是主要的影響效率的地方。 再來討論右邊的輸入,當(dāng)網(wǎng)卡收到數(shù)據(jù)時,中斷處理程序ex_intr將被調(diào)用。驅(qū)動通過ex_rx_intr將數(shù)據(jù)從硬件緩沖復(fù)制進m_buf數(shù)據(jù)結(jié)構(gòu)中,并調(diào)用ether_input來進一步處理。ether_input通過ether_demux進行分用。如果是一個Ip包,將通過軟中斷調(diào)用ip_fastforward進行數(shù)據(jù)校驗,并判斷是否要轉(zhuǎn)發(fā),如果失敗,將進行ip_input進行完整的處理。在in_input中,同樣要判斷是否要進行轉(zhuǎn)發(fā),如果不用,調(diào)用tcp_input進行進一步處理。在tcp_input中,進行數(shù)據(jù)校驗和驗證后,有一個叫做首部預(yù)測算法的優(yōu)化,可以加快數(shù)據(jù)處理速度。進行完所有的操作后,如果是用戶數(shù)據(jù),將喚醒用戶進程進行處理。同理,用戶可以使用多個函數(shù)進行數(shù)據(jù)接收,而soreceive將負責(zé)將數(shù)據(jù)從m_buf轉(zhuǎn)移至用戶進程緩沖。 可以看出,在FreeBSD中,發(fā)送和接收數(shù)據(jù),所進行的操作差不多,都要進行兩次數(shù)據(jù)復(fù)制和兩次數(shù)據(jù)遍歷,這也是最大的影響效率的地方。兩次數(shù)據(jù)復(fù)制似乎無可避免,下面我們來看看Linux是怎么做的。
可以看到,在LINUX上的實現(xiàn)稍顯復(fù)雜。讓我們首先從發(fā)送開始分析。在LINUX上,socket被實現(xiàn)為一個文件系統(tǒng),這樣可以通過vfs的write來調(diào)用,也可以直接使用send來調(diào)用,它們最終都是調(diào)用sock_sendmsg。Sock_sendmsg通過它的內(nèi)核版本__sock_sendmsg直接調(diào)用tcp_sendmsg來發(fā)送數(shù)據(jù)。在tcp_sendmsg中,同時完成數(shù)據(jù)復(fù)雜和數(shù)據(jù)校驗,這樣節(jié)省了一次遍歷操作,這也是和FreeBSD不同的地方。Linux使用skb結(jié)構(gòu)來管理數(shù)據(jù)緩沖,這和FreeBSD的m_buf大同小異。當(dāng)復(fù)制完數(shù)據(jù)后,使用tcp_push來進行下一步發(fā)送。Tcp_push通過__tcp_push_pending_frames來調(diào)用tcp_write_xmit將數(shù)據(jù)填入tcp的發(fā)送緩沖區(qū)。這里的填充僅是指針引用而已。下一步,tcp_transmit_skb將數(shù)據(jù)放入IP的發(fā)送隊列。Ip_queue_xmit函數(shù)完成IP包頭的設(shè)置以及數(shù)據(jù)效驗,并調(diào)用ip_output進入下一步發(fā)送。如果不用分片,將使用ip_finish_output繼續(xù)發(fā)送。在這里,填充數(shù)據(jù)的以太網(wǎng)包頭后調(diào)用dev_queue_xmit函數(shù)來進一步處理。Dev_queue_xmit函數(shù)將數(shù)據(jù)轉(zhuǎn)移至網(wǎng)絡(luò)核心層的待發(fā)送隊列,調(diào)用具體的驅(qū)動程序cp_start_xmit來完成數(shù)據(jù)的最終發(fā)送。最后的cp_start_xmit做的事情和freebsd的相應(yīng)函數(shù)差不多,檢查數(shù)據(jù),并復(fù)制進硬件緩沖。 當(dāng)接收到一個數(shù)據(jù)包的時候,網(wǎng)卡會產(chǎn)生中斷,這樣網(wǎng)卡驅(qū)動的cp_interrupt會被調(diào)用。cp_interrupt做的事情很少,只進行必要的檢查后就返回了,更多的事情通過cp_rx_poll來完成,cp_rx_poll在軟中斷中被調(diào)用,這樣做是為了提高驅(qū)動的處理效率。Cp_rx_poll做的事情主要就是把申請并將數(shù)據(jù)復(fù)制進一個skb緩沖中。netif_rx函數(shù)將數(shù)據(jù)從這個隊列中轉(zhuǎn)移至網(wǎng)絡(luò)核心層隊列中,netif_receive_skb從這里接收數(shù)據(jù),調(diào)用ip_rcv來處理。Ip_rc和ip_rcv_finish一起檢查數(shù)據(jù),得到包的路由,并調(diào)用相應(yīng)的input函數(shù)來完成路由,在這里就是ip_local_deliver,ip_local_deliver完成IP包的重組后,使用ip_local_deliver_finish來進入tcp的處理流程,tcp_v4_rcv完成數(shù)據(jù)校驗以及一些簡單的檢查,主要的工作在tcp_v4_do_rcv中完成。tcp_v4_do_rcv先判斷是否正常的用戶數(shù)據(jù),如果是則用tcp_rcv_established處理,否則用tcp_rcv_state_process來更新連接的狀態(tài)機。tcp_rcv_established中同樣有首部預(yù)測。如果一切順便,將喚醒等待在tcp_recvmsg中的用戶進程。后者將數(shù)據(jù)從skb緩沖中復(fù)制進用戶進程緩沖。并進行逐級返回。 通過以上分析不難看出,Linux的代碼比較混亂,可讀性沒有FreeBSD的好,比如說,Linux省略了以太網(wǎng)層,而且在接收數(shù)據(jù)中有多次異步操作,也許這將會影響內(nèi)核的穩(wěn)定性,F(xiàn)reeBSD的代碼就比較清晰,程序處理一目了然,可讀性也高,最穩(wěn)定的操作系統(tǒng)名不虛傳。這也可以從兩個操作系統(tǒng)的起源得到解釋。Linux起源于互聯(lián)網(wǎng)時代,由眾多愛好者一起完成,并沒有一個完整的規(guī)劃,代碼也多次經(jīng)過變動,而作者水平也參次不齊,造成現(xiàn)在的樣子。而FreeBSD系出名門,一直由一個獨立的小組進行維護,多年來更新不大,只有少許優(yōu)化,所以代碼的可讀性非常高。但從另一方面講,不斷更新的Linux在代碼方面比較激進,比如Linux使用skb緩沖效率要較FreeBSD使用的m_buf為高,這里限于篇幅,就不再具體分析了。而且linux發(fā)送數(shù)據(jù)時,在復(fù)制數(shù)據(jù)的同時完成的tcp的效驗,這樣就節(jié)省了一次數(shù)據(jù)的遍歷操作。也提高了效率。 通過以上比較我們不難得出結(jié)論,如果效率為先,則Linux當(dāng)為首推,如果穩(wěn)定至上,F(xiàn)reeBSD應(yīng)該為不二之選。不過,這兩個操作系統(tǒng)都是非常優(yōu)秀并久經(jīng)考驗,之間的差別也僅存于字面分析上。 ps:Linux 2.6 ip協(xié)議棧源碼分析:http://download.csdn.net/detail/fenggui/9177853 |
|
來自: 立志德美 > 《網(wǎng)絡(luò)》