在setsockopt函數中經常使用Socket選項對socket進行一些必要的設置,使socket能夠按咱們預期的特性去工做。 linux
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)。 socket
上層代碼若是要獲取內核協議棧爲網絡幀打的時間戳,就須要拿到附加數據,很顯然,咱們要拿的是SCM_TIMESTAMP類型的附加數據。 ide
咱們要在收到的報文中遍歷附加數據(可能有不少筆附加數據),可使用CMSG_FIRSTHDR()與CMSG_NXTHDR()宏在附加數據對象中進行遍歷,if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP)條件一旦成立,就代表已經找到了SCM_TIMESTAMP類型的附加數據,那就是以前內核協議棧爲這一幀網絡報文打上的時間戳,也就是收到此網絡報文的時間。 函數
這個特性在PTP協議中很是有用,要作網絡時間同步,必須有辦法知道網絡報文收到的時間,若是沒有硬件時間戳(精密PHY),上層應用程序就須要使用此特性獲取網絡幀收到時的時間戳,或者本身編寫內核模塊代碼接入底層協議棧,加蓋軟件時間戳。google