利用winpcap测量DNS查询时延和TCP连接时延

最近由于做毕业设计需要进行网络连接时延参数的测量,自己也搜了一下,没有找到太多想要的内容,幸而最后还是自己研究出来了,特在此分享一下:

在这里我测量DNS查询时延和TCP连接时延用的是winpcap,它是一个基于Win32平台的,用于捕获网络数据包并进行分析的开源库,如果没有学过,可以点击这里看一下教程,用个一两天就能学会。

网络编程的第一步当然是建立结构体

 

//ipv4首部
typedef struct ip_header
{
	u_char ver_ihl;		//版本+首部长度共8bit
	u_char tos;		//服务类型
	u_short tlen;		//总长
	u_short identification;	//标识
	u_short flags_fo;	//标志位3bit,段偏移量13bit
	u_char ttl;		//存活时间
	u_char proto;		//协议
	u_short crc;		//首部校验和
	ip_address saddr;	//源地址
	ip_address daddr;	//目标地址
	u_int op_pad;		//选项与填充
}ip_header;

//udp首部
typedef struct udp_header
{
	u_short sport;	//源端口
	u_short dport;	//目标端口
	u_short len;	//udp数据包长度
	u_short crc;	//校验和
}udp_header;

//dns首部
typedef struct dns_header
{
	u_short id;	//标识
	u_short flag;	//标志
}dns_header;

 //定义TCP首部
typedef struct tcp_header            
{ 
    u_short sport;              //16位源端口 
    u_short dport;              //16位目的端口 
    unsigned int seq;         	//32位序列号 
    unsigned int ack;         	//32位确认号
    unsigned char lenres;       //4位首部长度/6位保留字
    unsigned char flag;         //8位标志位 
    u_short win;                //16位窗口大小 
    u_short sum;                //16位校验和 
    u_short urp;                //16位紧急数据偏移量 
}tcp_header;	//版本+首部长度共8bit
	u_char tos;		//服务类型
	u_short tlen;		//总长
	u_short identification;	//标识
	u_short flags_fo;	//标志位3bit,段偏移量13bit
	u_char ttl;		//存活时间
	u_char proto;		//协议
	u_short crc;		//首部校验和
	ip_address saddr;	//源地址
	ip_address daddr;	//目标地址
	u_int op_pad;		//选项与填充
}ip_header;

//udp首部
typedef struct udp_header
{
	u_short sport;	//源端口
	u_short dport;	//目标端口
	u_short len;	//udp数据包长度
	u_short crc;	//校验和
}udp_header;

//dns首部
typedef struct dns_header
{
	u_short id;	//标识
	u_short flag;	//标志
}dns_header;

 //定义TCP首部
typedef struct tcp_header            
{ 
    u_short sport;              //16位源端口 
    u_short dport;              //16位目的端口 
    unsigned int seq;         	//32位序列号 
    unsigned int ack;         	//32位确认号
    unsigned char lenres;       //4位首部长度/6位保留字
    unsigned char flag;         //8位标志位 
    u_short win;                //16位窗口大小 
    u_short sum;                //16位校验和 
    u_short urp;                //16位紧急数据偏移量 
}tcp_header;


总共四个结构体,但是要说明的是,这里的DNS首部是经过简化的,实际的DNS协议报文结构如下:

 

因为DNS 查询时延是指从“终端向DNS服务器发起查询请求”到“终端收到DNS 服务器成功响应”之间的时间间隔。DNS传输层采用UDP 协议,知名端口号为53。从DNS 协议头的标志(flags)字段中的QR 字段,可以判断一个DNS 消息的类型(是查询还是响应等),而一对DNS 请求与响应消息有相同的标志(Transaction ID),我们通过Transaction ID 就可以确定哪个响应消息是与哪个请求消息对应的,那么对应的两条消息之间的间隔自然就是DNS查询时延了,所以只取标识和标志两个作为首部内容就可以了。

然后就是主要代码了

 

	struct tm *ltime;
	char timestr[16];
	time_t local_tv_sec;
	time_t local_tv_usec

	ip_header *ih;
	udp_header *uh;
	dns_header *dnsh;
	tcp_header *th;

	u_int ip_len;
	u_int tcp_header_len;
	u_int tcp_body_len;

	time_t time_dnsr[10];		//dns请求
	time_t time_dnsq[10];		//dns回应
	memset(time_dnsr,0,sizeof(time_dnsr));
	memset(time_dnsq,0,sizeof(time_dnsq));
	time_t time_tcp_1=0;
	time_t time_tcp_2=0;
	time_t time_tcp_3=0;

	while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0)
	{
		if(res == 0)
			/* Timeout elapsed */
			continue;
		
		//将时间戳转换为可识别的格式
		local_tv_sec=header->ts.tv_sec;
		local_tv_usec=header->ts.tv_usec;

		//获取ip数据包头部的位置
		ih=(ip_header*)(pkt_data+14);	//都是按字节算的
		//获取udp首部的位置
		ip_len=(ih->ver_ihl & 0xf)*4;

		if(ih->proto==0x11)
		{
			uh=(udp_header*)((u_char*)ih+ip_len);
			
			//获取dns首部的位置
			dnsh=(dns_header*)((u_char*)uh+8);

			if(dnsh->flag==0x8081)
				{
					time_dnsr[i]=local_tv_sec*1000000+local_tv_usec;	//单位是微妙
					if(time_dnsq[i]!=0 && time_dnsr[i]!=0)
					{	
						dns_delay=time_dnsr[i]-time_dnsq[i];
						printf("\nDNS查询时延:%d ms \n",dns_delay);
						memset(time_dnsr,0,sizeof(time_dnsr));
						memset(time_dnsq,0,sizeof(time_dnsq));
					}
					i++;
				}
			else
				{
					time_dnsq[j]=local_tv_sec*1000000+local_tv_usec;
					j++;
				}
		}
		else if(dns_delay)
		{
			th=(tcp_header*)((u_char*)ih+ip_len);	//unsigned char占一个字节
			//tcp数据包头部长度
			tcp_header_len=(((th->lenres<<4)|(th->lenres>>4)) & 0xf)*4;
		
			if(th->flag==0x02)
			{
				time_tcp_1=(local_tv_sec*1000000+local_tv_usec);
			}
			if(th->flag==0x12 && time_tcp_1!=0)
			{
				time_tcp_2=(local_tv_sec*1000000+local_tv_usec);
			}
			if(th->flag==0x10 && time_tcp_1!=0 && time_tcp_2!=0 && time_tcp_3==0)
			{
				time_tcp_3=(local_tv_sec*1000000+local_tv_usec);
				printf("TCP连接时延:%.6d us\n",time_tcp_3-time_tcp_1);	//都是按字节算的
		//获取udp首部的位置
		ip_len=(ih->ver_ihl & 0xf)*4;

		if(ih->proto==0x11)
		{
			uh=(udp_header*)((u_char*)ih+ip_len);
			
			//获取dns首部的位置
			dnsh=(dns_header*)((u_char*)uh+8);

			if(dnsh->flag==0x8081)
				{
					time_dnsr[i]=local_tv_sec*1000000+local_tv_usec;	//单位是微妙
					if(time_dnsq[i]!=0 && time_dnsr[i]!=0)
					{	
						dns_delay=time_dnsr[i]-time_dnsq[i];
						printf("\nDNS查询时延:%d ms \n",dns_delay);
						memset(time_dnsr,0,sizeof(time_dnsr));
						memset(time_dnsq,0,sizeof(time_dnsq));
					}
					i++;
				}
			else
				{
					time_dnsq[j]=local_tv_sec*1000000+local_tv_usec;
					j++;
				}
		}
		else if(dns_delay)
		{
			th=(tcp_header*)((u_char*)ih+ip_len);	//unsigned char占一个字节
			//tcp数据包头部长度
			tcp_header_len=(((th->lenres<<4)|(th->lenres>>4)) & 0xf)*4;
		
			if(th->flag==0x02)
			{
				time_tcp_1=(local_tv_sec*1000000+local_tv_usec);
			}
			if(th->flag==0x12 && time_tcp_1!=0)
			{
				time_tcp_2=(local_tv_sec*1000000+local_tv_usec);
			}
			if(th->flag==0x10 && time_tcp_1!=0 && time_tcp_2!=0 && time_tcp_3==0)
			{
				time_tcp_3=(local_tv_sec*1000000+local_tv_usec);
				printf("TCP连接时延:%.6d us\n",time_tcp_3-time_tcp_1);
time_tcp_1=0; time_tcp_2=0; time_tcp_3=0;

}

 
		}}
	}}

运行结果如下
 

 
 

 

关注公众号,掌握更多多媒体领域知识与资讯

文章帮到你了?可以扫描如下二维码进行打赏~,打赏多少您随意~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhanghui_cuc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值