在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