1. 程式人生 > >《Unix網路程式設計》中未提及的Socket選項

《Unix網路程式設計》中未提及的Socket選項

在setsockopt函式中常用Socket選項對socket進行一些必要的設定,使socket可以按我們預期的特性去工作。    

    SO_TIMESTAMP,一個Socket選項,在權威著作《Unix網路程式設計》中未提及到,即使在google上也難找到其詳細解釋與用法。然而在開原始碼ptpv2d-rc1中用到了這個socket選項,那麼它到底是用來做什麼的呢。

    分析過linux-2.6.32核心原始碼後,發現通過設定此選項,我們可以讓核心協議棧在接受到一個網路幀時為其打上時間戳,並將此時間戳作為一筆附加資料,與網路幀資料一起遞交到上層協議。

    netif_receive_skb(),linux核心協議棧中的關鍵函式,通常在網絡卡驅動程式poll函式(RX中斷處理函式會排程poll函式,詳情參考最新核心機制NAPI)的最後一步呼叫,佔們用來處理網路幀,並將網路幀遞交至上層協議,而netif_receive_skb函式第一件要做的事就是呼叫net_timestamp,為當前收到的網路幀打時間戳(net_timestamp函式裡會判斷是否已經使能了網路時間戳功能,即netstamp_need),並將此時間戳作為一筆SCM_TIMESTAMP型別的附加資料插入sk_buff(即cmsg)。    

    上層程式碼如果要獲取核心協議棧為網路幀打的時間戳,就需要拿到附加資料,很顯然,我們要拿的是SCM_TIMESTAMP型別的附加資料。 

    我們要在收到的報文中遍歷附加資料(可能有很多筆附加資料),可以使用CMSG_FIRSTHDR()與CMSG_NXTHDR()巨集在附加資料物件中進行遍歷,if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP)條件一旦成立,就表明已經找到了SCM_TIMESTAMP型別的附加資料,那就是之前核心協議棧為這一幀網路報文打上的時間戳,也就是收到此網路報文的時間。    

    這個特性在PTP協議中非常有用,要做網路時間同步,必須有辦法知道網路報文收到的時間,如果沒有硬體時間戳(精密PHY),上層應用程式就需要使用此特性獲取網路幀收到時的時間戳,或者自己編寫核心模組程式碼接入底層協議棧,加蓋軟體時間戳。