相信自己,快乐每一天
分类: LINUX
2013-11-05 09:12:10
在IP报文的首部和ICMP报文的首部都可以放入时间戳数据。clockdiff程序正是使用时间戳来测算目的主机和本地主机的系统时间差。
首先由上面的得出在RRT不大的时候,几个ICMP时间戳的关系。本地主机和202.38.64.9之间的时间差约为:-857514+248-251=-857517。
分别用-o(IP选项中时间戳)和不带选项(ICMP路由时间戳)上述路由的系统时间进行测试。
得到的结果:
两种方法测试的都比较准确.
上面是测试一个RTT较大的目的主机和本地主机的系统时间差。不过在使用clockdiff的时候,需要一点运气,因为很多路由会忽略ICMP或IP时间戳。
对clockdiff选项的解释如下:
-o
使用IP时间戳选项来测量系统时间差。时间戳只用3个。
-o1
使用IP时间戳选项来测量系统时间差。用4个时间戳。如果-o和-o1都没有设置,那么就是用ICMP时间戳来测试系统时间差。
int main(int argc, char *argv[]);
主函数。
在这个函数里:取得用户输入的选项,并根据这些选项及其参数设置相应的标识和参数值。然后取得ICMP报文的套接字。如果设置-o或者-o1选项,设置IP报文的套接字时间戳选项,且调用measure_opt()函数来使用IP时间戳选项来测量本地主机和服务器主机的系统时间差。如果没有设置-o或者-o1选项,并调用measure()函数来使用ICMP时间戳报文来测量本地主机和服务器主机的系统时间差。测量完成后,打印出测试信息或者出错信息。
int measure_opt(struct sockaddr_in * addr);
使用IP时间戳选项来测量本地主机和服务器主机的系统时间差。
函数设置ICMP的报文,并发送出去。然后,程序接受ICMP报文,取得IP时间戳选项,并计算本地主机和服务器系统时间差。
int measure(struct sockaddr_in * addr);
使用ICMP时间戳报文来测量本地主机和服务器主机的系统时间差。
函数设置ICMP的报文,并发送出去。然后,程序接受ICMP报文,取得ICMP时间戳选项,并计算本地主机和服务器系统时间差。
int interactive = 0;
标识标准输入输出是不是和一个终端相连,如果是就输出比较详细的信息,否则只输出必要数据。
例如clockdiff -o >a.txt,就只会输出三个数据,因为标准输出被重定向到了文件的写入里,不与终端相连。
int id;
当前进程的ID,放在ICMP时间戳请求和应答报文中的标识符中。
在接受到ICMP回复报文时,用这个标识符来判断ICMP报文是不是本进程发出的ICMP报文的回复报文。
int sock;
?
int sock_raw;
ICMP报文的套接字。
struct sockaddr_in server;
服务器主机的地址。
要对比本机和目的主机的系统时间,目的主机就相当于一个服务器。
int ip_opt_len = 0;
ip_opt_len是ip选项中用来存储时间戳的长度
可以通过-o和-o1选项来设置。
如果选择-o选项,则ip_opt_len为4 + 4*8,也就是可以在IP选项中存储4个IP时间戳。时间戳的组织形式为:
如果选择-o1选项,则ip_opt_len为4 + 3*8,也就是可以在IP选项中存储3个IP时间戳。时间戳的组织形式为:
#define BIASP 43199999
程序通过计算时间戳中标明的时间来计算本地主机和服务器主机的系统时间差。在系统时间发生回绕的时候,会出现系统时间差的计算问题。这里BIASP就是为了解决这个问题。
在假设本地主机和服务器的系统时间差最多不超过12个小时(即43200000毫秒)的情况下:
对于主机发送报文,如果本地主机在发送报文的时刻,本地主机系统时间已经超过0点。而该报文到达服务器主机的时刻,服务器主机系统时间仍然没有超过0点,则两个时间戳的差值(接受时间减去发送时间)会大于BIASP毫秒。
同样,对于逆过程(主机接受服务器的报文),如果服务器主机在发送报文的时刻,服务器主机系统时间已经超过0点。而该报文到达本地主机的时刻,本地主机系统时间仍然没有超过0点,则两个时间戳的差值也会大于BIASP毫秒。
#define BIASN -43200000
与BIASP类似,BIASN也是为了解决系统时间回绕不一致的问题。
在假设本地主机和服务器的系统时间差最多不超过12个小时(即43200000毫秒)的情况下:
对于主机发送报文,如果本地主机在发送报文的时刻,本地主机系统时间没有超过0点。而该报文到达服务器主机的时刻,服务器主机系统时间已经超过0点,则两个时间戳的差值会小于BIASN毫秒。
同样,对于逆过程(主机接受服务器的报文),如果服务器主机在发送报文的时刻,服务器主机系统时间没有超过0点。而该报文到达本地主机的时刻,本地主机系统时间已经超过0点,则两个时间戳的差值也会小于BIASN毫秒。
为了解决系统时间回绕不一致的问题,当时间差不处在BIASN和BIASP之间的情况下,则将它们对应到这个去区间内。特别需要强调的是这里有基本假设:本地主机和服务器的系统时间差最多不超过12个小时(即43200000毫秒)。如果不满足这个假设,这种对应关系是错误的。
#define MODULO 86400000
24个小时就是86400000毫秒,与在BIASN和BIASP一起处理系统时间回绕问题。
#define PROCESSING_TIME 0
由于记录时间和报文发送的准确时间会有一定的偏差,所以这类处理过程消耗的时间可能会对最终计算出来的系统时间差会产生一个偏移量的影响。这里PROCESSING_TIME就是为了消除这个偏移量的影响的。这里忽略了这个偏移量。而且可以预见的是,想要分析和给出偏移量的影响大小并不容易,因为它与太多的变量有关系。
#define PACKET_IN 1024
接受报文的存储字节数。
int measure_delta;
计算的系统时间差。
计算的系统时间差有两种假设,measure_delta1是另一种假设下的计算结果。
int measure_delta1;
计算的系统时间差。
计算的系统时间差有两种假设,measure_delta是另一种假设下的计算结果。
static u_short seqno;
发送报文的序列号。
每次发送报文都设置ICMP报文的序列号为seqno,seqno递加。
static u_short seqno0;
发送报文的最小序列号。
当接受到报文时要判断ICMP报文的序列号是不是介于seqno0和seqno之间,否则将不认为这个ICMP报文是本程序的恢复报文。
static u_short acked;
接受到ICMP回复报文的最大序列号。
当接受到报文时,如果ICMP报文的序列号大于现在的acked,则更新acked。
long rtt = 1000;
对RTT的预测。
预测方法是使用指数加权移动平均。
和rtt_sigma一起用来设置超时时间,用的就是Jacobson/Karels算法。
long min_rtt;
RTT的最小值。
long rtt_sigma = 0;
对RTT预测的误差。
和rtt一起用来设置超时时间,用的就是Jacobson/Karels算法。
clockdiff程序使用Jacobson/Karels算法,使用以前的RTT实测值来预测下一次的RTT,并设定传输时间超时值。
Jacobson/Karels算法在[[1]]文中有介绍。伪代码如下:
Difference = SampleRTT - EstimatedRTT
EstimatedRTT = EstimatedRTT + (δ × Difference)
Deviation = Deviation + δ × (|Difference| - Deviation)
TimeOut = μ × EstimatedRTT + φ × Deviation
其中:
SampleRTT是测量所得的新的RTT数据。
EstimatedRTT是预测的RTT值。
Deviation是预测的偏差值。
TimeOut是超时时间值。
δ为0到1之间的常数。
μ和φ均是一个常数。
在clockdiff程序的实现中:
δ设置为1/4。
μ和φ均设置为1。
相关函数:
int measure_opt(struct sockaddr_in * addr)void main_loop(inticmp_sock, __u8 *packet, int packlen);
int measure(struct sockaddr_in * addr);
设两台主机的系统时间相差detaT,即源主机的系统时间为T的时刻,目的主机的系统时间为T+detaT。
通过ICMP时间戳或者IP选项时间戳,可以获得如下信息:
delta1:接受时间戳减去发起时间戳。
delta2:接到回复报文时间减传送时间戳。
时间戳的插入过程如下图所示:
由上图可以知道:
delta1 = (T + dataT + RTT/2) – T = RTT/2+detaT
delta2 = (T + RTT) - (T + dataT + RTT/2) =RTT/2-detaT
故此(delta1 - delta2) / 2就是两个主机之间的系统时间差。
由于一次测量的delta1和delta2可能会由于网络拥塞情况的变化而发生较大偏差,故此在实际的实现中多次测量求较优值。引入了如下几个变量:
min1:多次传送中delta1的最小值。
min2:多次传送中delta2的最小值。
min_rtt:多次传送中delta1+delta2的最小值。
PROCESSING_TIME:处理过程中所消耗的时间。
在基于以下的几个基本假设情况下,可以测算系统时间的差值:
1. RTT中发送到目的主机的时间和返回源主机的时间基本相等都为RTT/2。
2. 当min1最小时,min1是对RTT/2+detaT的较优预测。同样,当min2最小时,min2是对RTT/2-detaT的较优预测。故此,(min1 - min2)/2是对deltaT的较优预测。这种预测方法的系统时间差预测值存储为变量measure_delta。
3. 当min_rtt最小时,(delta1 - delta2)/2也是对deltaT的较优预测。这种预测方法的系统时间差预测值存储为变量measure_delta1。
4. 各主机从接受到报文到记录接受到报文时间,这两个时刻的时间间隔为可以忽略;即发送和接受报文的处理过程中所消耗的时间可以忽略。实际上PROCESSING_TIME正是用来消除由处理过程的时间造成的对于计算出来的系统时间差别的影响。不过这里PROCESSING_TIME设置为0,认为处理消耗时间可以忽略。
以上的假设决定了clockdiff测算出来的系统时间差别的不准确性。
相关函数:
int measure_opt(struct sockaddr_in * addr)void main_loop(inticmp_sock, __u8 *packet, int packlen);
int measure(struct sockaddr_in * addr);
本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article