计算机网络课程设计-Tracert 与 Ping 程序设计与实现

目录

前言

1 实验题目

2 实验目的

3 实验内容

3.1 步骤

3.2 关键代码

3.2.1 发送ICMP数据报

3.2.2 解析收到的数据报

4 实验结果与分析

5 代码

5.1 ping代码

5.2 Tracert代码


前言

        本实验为计算机网络课程设计内容,基本上所有代码都是根据指导书给的附录写出来的。有些实验需要实现图形界面,但是出于期末考试压力,我所有实验均是在控制台输入输出的,没有花额外时间去学习qt了,有精力的同学可以自学一下qt实现简单的图形界面。同时,该博客内容为部分报告内容,仅为大家提供参考,请勿直接抄袭。另外,本次实验所用平台是dev c++5.11

1 实验题目

        实验二 Tracert 与 Ping 程序设计与实现

2 实验目的

        了解 Tracert 程序的实现原理,并调试通过。然后参考 Tracert 程序和教材 4.4.2 节,编写一个 Ping 程序,并能测试本局域网的所有机器是否在线。

3 实验内容

3.1 步骤

        (1)使用Socket建立网络连接。

        (2)构造ICMP报文。

        (3)发送ICMP请求并接收回显应答。

        (4)解析回显应答,进行主机在线状态的判断。

3.2 关键代码

3.2.1 发送ICMP数据报

//发送 TCP 回显请求信息
sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(sockaddr*)&destSockAddr,sizeof(destSockAddr));

3.2.2 解析收到的数据报

//对数据包进行解码
BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE
                        ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) {
	//检查数据报大小的合法性
	IP_HEADER* pIpHdr = (IP_HEADER*)pBuf;
	int iIpHdrLen = pIpHdr->hdr_len * 4;
	if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER)))
		return FALSE;
	//根据 ICMP 报文类型提取 ID 字段和序列号字段
	ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iIpHdrLen);
	USHORT usID,usSquNo;
	if(pIcmpHdr->type==ICMP_ECHO_REPLY) { //ICMP 回显应答报文
		usID=pIcmpHdr->id; //报文 ID
		usSquNo=pIcmpHdr->seq; //报文序列号
	} else if(pIcmpHdr->type==ICMP_TIMEOUT) { //ICMP 超时差错报文
		char * pInnerIpHdr=pBuf+iIpHdrLen+sizeof(ICMP_HEADER); //载荷中的 IP 头
		int iInnerIPHdrLen=((IP_HEADER *)pInnerIpHdr)->hdr_len*4; //载荷中的 IP 头长
		ICMP_HEADER * pInnerIcmpHdr=(ICMP_HEADER *)(pInnerIpHdr+iInnerIPHdrLen);//载荷中的 ICMP 头
		usID=pInnerIcmpHdr->id; //报文 ID
		usSquNo=pInnerIcmpHdr->seq; //序列号
	} else {
		return false;
	}
	//检查 ID 和序列号以确定收到期待数据报
	if(usID!=(USHORT)GetCurrentProcessId()||usSquNo!=DecodeResult.usSeqNo) {
		return false;
	}
	//记录 IP 地址并计算往返时间
	DecodeResult.dwIPaddr.s_addr=pIpHdr->sourceIP;
	DecodeResult.dwRoundTripTime=GetTickCount()-DecodeResult.dwRoundTripTime;
	//处理正确收到的 ICMP 数据报
	if (pIcmpHdr->type == ICMP_ECHO_REPLY ||pIcmpHdr->type == ICMP_TIMEOUT) {
		//输出往返时间信息
		if(DecodeResult.dwRoundTripTime)
			cout<<" 时间="<<DecodeResult.dwRoundTripTime<<"ms"<<flush;
		else
			cout<<" "<<"时间<1ms"<<flush;
	}
	return true;
}

4 实验结果与分析

对地址范围192.168.0.106-108进行测试,可以从打印的结果看到哪些主机在线,同时可以验证程序的正确性。

图1.1 对某个地址范围进行测试

5 代码

5.1 ping代码

刚开始我是用traceroute直接改造的,但是有问题,后面我又改了代码,这个代码的前一个版本在输入不同跳数的时候有点问题,这个最新的代码我测试不同跳数的时候是没有问题,但是不知道有没有改出其他的毛病,所以下面附上源程序在5.2

/* 程序名称:路由追踪(Tracert)程序
实现原理:Tracert 程序关键是对 IP 头部生存时间(time to live)TTL 字段的使用,程序实现时是向目
地主机发送一个 ICMP 回显请求消息,初始时 TTL 等于 1,这样当该数据报抵达途中的第一个路由器
时,TTL 的值就被减为 0,导致发生超时错误,因此该路由生成一份 ICMP 超时差错报文返回给源主
机。随后,主机将数据报的 TTL 值递增 1,以便 IP 报能传送到下一个路由器,并由下一个路由器生成
ICMP 超时差错报文返回给源主机。不断重复这个过程,直到数据报达到最终的目地主机,此时目地
主机将返回 ICMP 回显应答消息。这样,源主机只需对返回的每一份 ICMP 报文进行解析处理,就可
以掌握数据报从源主机到达目地主机途中所经过的路由信息。
*/
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include<map>
#include<vector>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
//IP 报头
typedef struct {
	unsigned char hdr_len:4; 		//4 位头部长度
	unsigned char version:4; 		//4 位版本号
	unsigned char tos; 				//8 位服务类型
	unsigned short total_len; 		//16 位总长度
	unsigned short identifier; 		//16 位标识符
	unsigned short frag_and_flags; 	//3 位标志加 13 位片偏移
	unsigned char ttl; 				//8 位生存时间
	unsigned char protocol; 		//8 位上层协议号
	unsigned short checksum; 		//16 位校验和
	unsigned long sourceIP; 		//32 位源 IP 地址
	unsigned long destIP; 			//32 位目的 IP 地址
} IP_HEADER;
//ICMP 报头
typedef struct {
	BYTE type; 		//8 位类型字段
	BYTE code;		 //8 位代码字段
	USHORT cksum; 	//16 位校验和
	USHORT id; 		//16 位标识符
	USHORT seq; 	//16 位序列号
} ICMP_HEADER;
//报文解码结构
typedef struct {
	USHORT usSeqNo; 		//序列号
	DWORD dwRoundTripTime; 	//往返时间
	in_addr dwIPaddr; 		//返回报文的 IP 地址
} DECODE_RESULT;

vector< pair<string,string> > IpAddressStatus1;

//计算网际校验和函数
USHORT checksum(USHORT *pBuf,int iSize) {
	unsigned long cksum=0;
	while(iSize>1) {
		cksum+=*pBuf++;
		iSize-=sizeof(USHORT);
	}
	if(iSize) {
		cksum+=*(UCHAR *)pBuf;
	}
	cksum=(cksum>>16)+(cksum&0xffff);
	cksum+=(cksum>>16);
	return (USHORT)(~cksum);
}
//对数据包进行解码
BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE
                        ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) {
	//检查数据报大小的合法性
	IP_HEADER* pIpHdr = (IP_HEADER*)pBuf;
	int iIpHdrLen = pIpHdr->hdr_len * 4;
	if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER)))
		return FALSE;
	//根据 ICMP 报文类型提取 ID 字段和序列号字段
	ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iIpHdrLen);
	USHORT usID,usSquNo;
	if(pIcmpHdr->type==ICMP_ECHO_REPLY) { //ICMP 回显应答报文
		usID=pIcmpHdr->id; //报文 ID
		usSquNo=pIcmpHdr->seq; //报文序列号
	} else if(pIcmpHdr->type==ICMP_TIMEOUT) { //ICMP 超时差错报文
		char * pInnerIpHdr=pBuf+iIpHdrLen+sizeof(ICMP_HEADER); //载荷中的 IP 头
		int iInnerIPHdrLen=((IP_HEADER *)pInnerIpHdr)->hdr_len*4; //载荷中的 IP 头长
		ICMP_HEADER * pInnerIcmpHdr=(ICMP_HEADER *)(pInnerIpHdr+iInnerIPHdrLen);//载荷中的 ICMP 头
		usID=pInnerIcmpHdr->id; //报文 ID
		usSquNo=pInnerIcmpHdr->seq; //序列号
	} else {
		return false;
	}
	//检查 ID 和序列号以确定收到期待数据报
	if(usID!=(USHORT)GetCurrentProcessId()||usSquNo!=DecodeResult.usSeqNo) {
		return false;
	}
//	cout<<" pIpHdrLen="<<htons(pIpHdr->total_len); //填充序列号<<" ";
	cout<<" bytes="<<(int)iPacketSize-iIpHdrLen-8<<" ";
	cout<<"ttl="<<(int)pIpHdr->ttl<<" ";
//	cout<<"Protocol:"<<(int)pIpHdr->protocol<<"\n";
	//记录 IP 地址并计算往返时间
	DecodeResult.dwIPaddr.s_addr=pIpHdr->sourceIP;
	DecodeResult.dwRoundTripTime=GetTickCount()-DecodeResult.dwRoundTripTime;
	//处理正确收到的 ICMP 数据报
	if (pIcmpHdr->type == ICMP_ECHO_REPLY ||pIcmpHdr->type == ICMP_TIMEOUT) {
		//输出往返时间信息
		if(DecodeResult.dwRoundTripTime)
			cout<<" 时间="<<DecodeResult.dwRoundTripTime<<"ms"<<flush;
		else
			cout<<" "<<"时间<1ms"<<flush;
	}
	return true;
}
int main(void) {
	//初始化 Windows sockets 网络环境
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,2),&wsa);
	char IpAddress[255];

	map<string,string> IpAddressStatus;
	int  ip1,ip2,ip3,ip4,ip5;
	int cnt = 255;
	int maxHops = 20;
	int maxTimeout=1000;
	cout<<"请输入一个 IP 地址范围(如192.168.142.119-255,只需要输入192 168 142 119 255):";
	cin>>ip1>>ip2>>ip3>>ip4>>ip5;
	cnt=ip5-ip4;
	while(ip1>255||ip2>255||ip3>255||ip4>255||cnt<0) {
		cout<<"输入的 IP 地址范围无效!请重新输入:"<<"\n";
		cin>>ip1>>ip2>>ip3>>ip4>>ip5;
		cnt=ip5-ip4;
	}
	cout<<"请输入超时时间(ms):";
	cin>>maxTimeout;
	cout<<"最大路由跳数:";
	cin>>maxHops;
	while(cnt>=0) {
//		if(ip1>255||ip2>255||ip3>255||ip4>255||) {
//			cout<<"输入的 IP 地址范围无效!请重新输入:"<<"\n";
//			cin>>ip1>>ip2>>ip3>>ip4>>ip5;
//			cnt=ip5-ip4;
//		}
		sprintf(IpAddress,"%d.%d.%d.%d",ip1,ip2,ip3,ip5-cnt);
		cnt--;
		//得到 IP 地址
		u_long ulDestIP=inet_addr(IpAddress);
		cout<<"\n正在 ping 的 ip 地址:"<<IpAddress<<"\n";
		//转换不成功时按域名解析
		if(ulDestIP==INADDR_NONE) {
			hostent * pHostent=gethostbyname(IpAddress);
			if(pHostent) {
				ulDestIP=(*(in_addr*)pHostent->h_addr).s_addr;
			} else {
				cout<<"输入的 IP 地址或域名无效!"<<endl;
				WSACleanup();
				return 0;
			}
		}
//		cout<<"Tracing route to "<<IpAddress<<" with a maximum of "<<maxHops<<" hops.\n"<<endl;
		//填充目地端 socket 地址
		sockaddr_in destSockAddr;
		ZeroMemory(&destSockAddr,sizeof(sockaddr_in));
		destSockAddr.sin_family=AF_INET;
		destSockAddr.sin_addr.s_addr=ulDestIP;
		//创建原始套接字
		SOCKET sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,
		                         WSA_FLAG_OVERLAPPED);
		//超时时间
		int iTimeout=maxTimeout;
		//接收超时
		setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout));
		//发送超时
//		setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout));
		//构造 ICMP 回显请求消息,并以 TTL 递增的顺序发送报文
		//ICMP 类型字段
		const BYTE ICMP_ECHO_REQUEST=8; //请求回显
		const BYTE ICMP_ECHO_REPLY=0; //回显应答
		const BYTE ICMP_TIMEOUT=11; //传输超时
		//其他常量定义
		const int DEF_ICMP_DATA_SIZE=32; //ICMP 报文默认数据字段长度
		const int MAX_ICMP_PACKET_SIZE=1024;//ICMP 报文最大长度(包括报头)
		const DWORD DEF_ICMP_TIMEOUT=maxTimeout; //回显应答超时时间
//		const int DEF_MAX_HOP=30; //最大跳站数
		const int DEF_MAX_HOP=maxHops; //最大跳站数
		//填充 ICMP 报文中每次发送时不变的字段

		char IcmpSendBuf[sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE];//发送缓冲区
		memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); //初始化发送缓冲区
		char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE]; //接收缓冲区
		memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); //初始化接收缓冲区
		ICMP_HEADER * pIcmpHeader=(ICMP_HEADER*)IcmpSendBuf;
		pIcmpHeader->type=ICMP_ECHO_REQUEST; //类型为请求回显
		pIcmpHeader->code=0; //代码字段为 0
		pIcmpHeader->id=(USHORT)GetCurrentProcessId(); //ID 字段为当前进程号
		memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE);//数据字段
		USHORT usSeqNo=0; //ICMP 报文序列号
		int iTTL=1; //TTL 初始值为 1
		BOOL bReachDestHost=FALSE; //循环退出标志
		int iMaxHot=DEF_MAX_HOP; //循环的最大次数
		DECODE_RESULT DecodeResult; //传递给报文解码函数的结构化参数
		int flag=0;
		int ping_ttl=4;
		while(!bReachDestHost&&ping_ttl--) {
			//设置 IP 报头的 TTL 字段
//			setsockopt(sockRaw,IPPROTO_IP,IP_TTL,(char *)&iTTL,sizeof(iTTL));
//			cout<<iTTL<<flush; //输出当前序号
			cout<<4-ping_ttl;
			//填充 ICMP 报文中每次发送变化的字段
			((ICMP_HEADER *)IcmpSendBuf)->cksum=0; //校验和先置为 0
			((ICMP_HEADER *)IcmpSendBuf)->seq=htons(usSeqNo++); //填充序列号
			((ICMP_HEADER *)IcmpSendBuf)->cksum=checksum((USHORT *)IcmpSendBuf,
			                                    sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE); //计算校验和
			//记录序列号和当前时间
			DecodeResult.usSeqNo=((ICMP_HEADER*)IcmpSendBuf)->seq; //当前序号
			DecodeResult.dwRoundTripTime=GetTickCount(); //当前时间
			//发送 TCP 回显请求信息
			sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(sockaddr*)&destSockAddr,sizeof(destSockAddr));
			//接收 ICMP 差错报文并进行解析处理
			sockaddr_in from; //对端 socket 地址

			int iFromLen=sizeof(from); //地址结构大小
			int iReadDataLen; //接收数据长度
			while(1) {
				//接收数据
				iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(sockaddr*)&from,&iFromLen);
//				cout<<"iReadDataLen:"<<iReadDataLen<<"\n";
//				cout<<"IcmpRecvBuf:"<<IcmpRecvBuf<<"\n";
				if(iReadDataLen!=SOCKET_ERROR) { //有数据到达
					//对数据包进行解码
					if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen,DecodeResult,ICMP_ECHO_REPLY,ICMP_TIMEOUT)) {
						//到达目的地,退出循环
						if(DecodeResult.dwIPaddr.s_addr==destSockAddr.sin_addr.s_addr)
//							bReachDestHost=true;
							flag=1;
						//输出 IP 地址
						cout<<'\t'<<inet_ntoa(DecodeResult.dwIPaddr)<<"\n";
//						IpAddressStatus[IpAddress] = "在线";
//						IpAddressStatus1.push_back(make_pair(IpAddress,"在线"));
						break;
					}
//					else{
//						IpAddressStatus1.push_back(make_pair(IpAddress,"在线"));
//						break;
//					}
				} else if(WSAGetLastError()==WSAETIMEDOUT) { //接收超时,输出*号
					cout<<" *"<<'\t'<<"Request timed out."<<endl;
//					IpAddressStatus1.push_back(make_pair(IpAddress,"不可达"));
					iTTL++;
					if(iTTL>6)break;
					break;
				} else {
					cout<<"错误\n";
					break;
				}
			}
//			iTTL++; //递增 TTL 值
		}
		if(flag) {
			IpAddressStatus1.push_back(make_pair(IpAddress,"在线"));
		} else {
			IpAddressStatus1.push_back(make_pair(IpAddress,"不可达"));
		}
//		if(iMaxHot <= 0) {
//			//cout<<"地址不可达\n";
			IpAddressStatus[IpAddress] = "不可达";
//			IpAddressStatus1.push_back(make_pair(IpAddress,"不可达"));
//		}
	}
	//迭代
	cout<<"----------------------------------------------------------\n";
	cout<<"ip 地址范围 "<<ip1<<"."<<ip2<<"."<<ip3<<"."<<ip4<<"-"<<ip5<<" 的 ping 情况:\n";
	for(vector< pair<string,string> > ::iterator it = IpAddressStatus1.begin(); it != IpAddressStatus1.end(); it++)
		cout<<(*it).first<<":\t\t"<<(*it).second<<"\n";//输出key 和value值
}

5.2 Tracert代码

/* 程序名称:路由追踪(Tracert)程序
实现原理:Tracert 程序关键是对 IP 头部生存时间(time to live)TTL 字段的使用,程序实现时是向目
地主机发送一个 ICMP 回显请求消息,初始时 TTL 等于 1,这样当该数据报抵达途中的第一个路由器
时,TTL 的值就被减为 0,导致发生超时错误,因此该路由生成一份 ICMP 超时差错报文返回给源主
机。随后,主机将数据报的 TTL 值递增 1,以便 IP 报能传送到下一个路由器,并由下一个路由器生成
ICMP 超时差错报文返回给源主机。不断重复这个过程,直到数据报达到最终的目地主机,此时目地
主机将返回 ICMP 回显应答消息。这样,源主机只需对返回的每一份 ICMP 报文进行解析处理,就可
以掌握数据报从源主机到达目地主机途中所经过的路由信息。
*/
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
using namespace std;
#pragma comment(lib, "Ws2_32.lib")
//IP 报头
typedef struct {
	unsigned char hdr_len:4; //4 位头部长度
	unsigned char version:4; //4 位版本号
	unsigned char tos; //8 位服务类型
	unsigned short total_len; //16 位总长度
	unsigned short identifier; //16 位标识符
	unsigned short frag_and_flags; //3 位标志加 13 位片偏移
	unsigned char ttl; //8 位生存时间
	unsigned char protocol; //8 位上层协议号
	unsigned short checksum; //16 位校验和
	unsigned long sourceIP; //32 位源 IP 地址
	unsigned long destIP; //32 位目的 IP 地址
} IP_HEADER;
//ICMP 报头
typedef struct {
	BYTE type; //8 位类型字段
	BYTE code; //8 位代码字段
	USHORT cksum; //16 位校验和
	USHORT id; //16 位标识符
	USHORT seq; //16 位序列号
} ICMP_HEADER;
//报文解码结构
typedef struct {
	USHORT usSeqNo; //序列号
	DWORD dwRoundTripTime; //往返时间
	in_addr dwIPaddr; //返回报文的 IP 地址
} DECODE_RESULT;
//计算网际校验和函数
USHORT checksum(USHORT *pBuf,int iSize) {
	unsigned long cksum=0;
	while(iSize>1) {
		cksum+=*pBuf++;
		iSize-=sizeof(USHORT);
	}
	if(iSize) {
		cksum+=*(UCHAR *)pBuf;
	}
	cksum=(cksum>>16)+(cksum&0xffff);
	cksum+=(cksum>>16);
	return (USHORT)(~cksum);
}
//对数据包进行解码
BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE
                        ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) {
//检查数据报大小的合法性
	IP_HEADER* pIpHdr = (IP_HEADER*)pBuf;
	int iIpHdrLen = pIpHdr->hdr_len * 4;
	if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER)))
		return FALSE;
//根据 ICMP 报文类型提取 ID 字段和序列号字段
	ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iIpHdrLen);
	USHORT usID,usSquNo;
	if(pIcmpHdr->type==ICMP_ECHO_REPLY) { //ICMP 回显应答报文
		usID=pIcmpHdr->id; //报文 ID
		usSquNo=pIcmpHdr->seq; //报文序列号
	} else if(pIcmpHdr->type==ICMP_TIMEOUT) { //ICMP 超时差错报文
		char * pInnerIpHdr=pBuf+iIpHdrLen+sizeof(ICMP_HEADER); //载荷中的 IP 头
		int iInnerIPHdrLen=((IP_HEADER *)pInnerIpHdr)->hdr_len*4; //载荷中的 IP 头长
		ICMP_HEADER * pInnerIcmpHdr=(ICMP_HEADER *)(pInnerIpHdr+iInnerIPHdrLen);//载荷中的 ICMP 头
		usID=pInnerIcmpHdr->id; //报文 ID
		usSquNo=pInnerIcmpHdr->seq; //序列号
	} else {
		return false;
	}
//检查 ID 和序列号以确定收到期待数据报
	if(usID!=(USHORT)GetCurrentProcessId()||usSquNo!=DecodeResult.usSeqNo) {
		return false;
	}
//记录 IP 地址并计算往返时间
	DecodeResult.dwIPaddr.s_addr=pIpHdr->sourceIP;
	DecodeResult.dwRoundTripTime=GetTickCount()-DecodeResult.dwRoundTripTime;
//处理正确收到的 ICMP 数据报
	if (pIcmpHdr->type == ICMP_ECHO_REPLY ||pIcmpHdr->type == ICMP_TIMEOUT) {
//输出往返时间信息
		if(DecodeResult.dwRoundTripTime)
			cout<<" "<<DecodeResult.dwRoundTripTime<<"ms"<<flush;
		else
			cout<<" "<<"<1ms"<<flush;
	}
	return true;
}
int main() {
//初始化 Windows sockets 网络环境
	WSADATA wsa;
	WSAStartup(MAKEWORD(2,2),&wsa);
	char IpAddress[255];
	cout<<"请输入一个 IP 地址或域名:";
	cin>>IpAddress;
//得到 IP 地址
	u_long ulDestIP=inet_addr(IpAddress);
//转换不成功时按域名解析
	if(ulDestIP==INADDR_NONE) {
		hostent * pHostent=gethostbyname(IpAddress);
		if(pHostent) {
			ulDestIP=(*(in_addr*)pHostent->h_addr).s_addr;
		} else {
			cout<<"输入的 IP 地址或域名无效!"<<endl;
			WSACleanup();
			return 0;
		}
	}
	cout<<"Tracing route to "<<IpAddress<<" with a maximum of 30 hops.\n"<<endl;
//填充目地端 socket 地址
	sockaddr_in destSockAddr;
	ZeroMemory(&destSockAddr,sizeof(sockaddr_in));
	destSockAddr.sin_family=AF_INET;
	destSockAddr.sin_addr.s_addr=ulDestIP;
//创建原始套接字
	SOCKET sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,
	                         WSA_FLAG_OVERLAPPED);
//超时时间
	int iTimeout=3000;
//接收超时
	setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout));
//发送超时
	setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout));
//构造 ICMP 回显请求消息,并以 TTL 递增的顺序发送报文
//ICMP 类型字段
	const BYTE ICMP_ECHO_REQUEST=8; //请求回显
	const BYTE ICMP_ECHO_REPLY=0; //回显应答
	const BYTE ICMP_TIMEOUT=11; //传输超时
//其他常量定义
	const int DEF_ICMP_DATA_SIZE=32; //ICMP 报文默认数据字段长度
	const int MAX_ICMP_PACKET_SIZE=1024;//ICMP 报文最大长度(包括报头)
	const DWORD DEF_ICMP_TIMEOUT=3000; //回显应答超时时间
	const int DEF_MAX_HOP=30; //最大跳站数
//填充 ICMP 报文中每次发送时不变的字段
	char IcmpSendBuf[sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE];//发送缓冲区
	memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); //初始化发送缓冲区
	char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE]; //接收缓冲区
	memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); //初始化接收缓冲区
	ICMP_HEADER * pIcmpHeader=(ICMP_HEADER*)IcmpSendBuf;
	pIcmpHeader->type=ICMP_ECHO_REQUEST; //类型为请求回显
	pIcmpHeader->code=0; //代码字段为 0
	pIcmpHeader->id=(USHORT)GetCurrentProcessId(); //ID 字段为当前进程号
	memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE);//数据字段
	USHORT usSeqNo=0; //ICMP 报文序列号
	int iTTL=1; //TTL 初始值为 1
	BOOL bReachDestHost=FALSE; //循环退出标志
	int iMaxHot=DEF_MAX_HOP; //循环的最大次数
	DECODE_RESULT DecodeResult; //传递给报文解码函数的结构化参数
	while(!bReachDestHost&&iMaxHot--) {
//设置 IP 报头的 TTL 字段
		setsockopt(sockRaw,IPPROTO_IP,IP_TTL,(char *)&iTTL,sizeof(iTTL));
		cout<<iTTL<<flush; //输出当前序号
//填充 ICMP 报文中每次发送变化的字段
		((ICMP_HEADER *)IcmpSendBuf)->cksum=0; //校验和先置为 0
		((ICMP_HEADER *)IcmpSendBuf)->seq=htons(usSeqNo++); //填充序列号
		((ICMP_HEADER *)IcmpSendBuf)->cksum=checksum((USHORT *)IcmpSendBuf,
		                                    sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE); //计算校验和
//记录序列号和当前时间
		DecodeResult.usSeqNo=((ICMP_HEADER*)IcmpSendBuf)->seq; //当前序号
		DecodeResult.dwRoundTripTime=GetTickCount(); //当前时间
//发送 TCP 回显请求信息
		sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(sockaddr*)&destSockAddr,sizeof(destSockAddr));
//接收 ICMP 差错报文并进行解析处理
		sockaddr_in from; //对端 socket 地址
		int iFromLen=sizeof(from); //地址结构大小
		int iReadDataLen; //接收数据长度
		while(1) {
//接收数据
			iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(sockaddr*)&from,&
			                      iFromLen);
			if(iReadDataLen!=SOCKET_ERROR) { //有数据到达
//对数据包进行解码
				if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen,DecodeResult,ICMP_ECHO_REPLY,ICMP_TIMEOUT)) {
//到达目的地,退出循环
					if(DecodeResult.dwIPaddr.s_addr==destSockAddr.sin_addr.s_addr)
						bReachDestHost=true;
//输出 IP 地址
					cout<<'\t'<<inet_ntoa(DecodeResult.dwIPaddr)<<endl;
					break;
				}
			} else if(WSAGetLastError()==WSAETIMEDOUT) { //接收超时,输出*号
				cout<<" *"<<'\t'<<"Request timed out."<<endl;
				break;
			} else {
				break;
			}
		}
		iTTL++; //递增 TTL 值
	}
}

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
试 题:《计算机网络课程设计》设计任务和考查内容包含以下四部分。 一、数据抓包和网络协议分析(要求写出抓包的主要截图、数据传输的分析过程及关键实验操作步骤) 1、 捕获ARP请求,ARP应答数据包,分析其组成特征。总结ARP协议运行的基本过程。 2、 捕获ICMP数据包,对其进行分析研究。(icmp请求数据包,icmp应答数据包) 3、 捕获TCP“三次握手”建立连接的数据包并分析;捕获TCP“2次两次握手”释放连接的数据包并分析。 a) tcp连接的建立 b) tcp连接的释放 4、 捕获HTTP,DNS,DHCP数据包,分析其构成。 a) http数据包的捕获与分析 b) DNS数据包的捕获与分析 5、 通过捕捉smtp协议包分析邮箱密码,并分析其工作过程。 提示:有些邮箱直接登录操作无法捕捉,如qq、163邮箱等。需要Web页面登录我的网易或QQ等邮箱,捕获数据并分析出密码。也可采用命令方式收发邮件状态下抓取账号密码数据。 二、网络编程设计(以下三题选择完成一个即可,要求有程序代码和运行结果) 1、 数据包的分析程序设计(不需图形界面,结果输出在命令行下)。 2、 简单的网络通信程序(包括服务器端程序,客户端程序,能实现客户端到服务器的主动连接,发送信息,服务器能否对信息做一次回应)。 3、 编写一个程序,能够根据输入的原始数据,及所选择的多项式,自动生成CRC校验码。 三、网络设备配置 从“CCNA 实验手册201806.doc”中自选两个项目,在机架或模拟器上完成,并写出主要的配置过程、实验数据、 相关截图和结论。其中所选实验要求包含交换机的Vlan配置和路由器的RIP、OSPF配置部分。 四、网络系统工程方案设计 以文华学院为背景,了解文华学院现有校园网络的构成。主要从网速提高,网络安全,无线网络构建等几个方面进行分析,并提出合理的改进意见,设计出更优的校园网络工程方案。 1、需求分析 以文华学院为背景,通过实地调查、现场访谈、书面调查等形式了解文华学院的组织结构、网络建设的背景,对文华学院的网络工程有一个全面的感性的认识。建设文华学院需要重新建立一个校园网,在前面了解的知识背景之上,明确网络需求和网络性能的评价标准。具体地,包括网络建设的目的与原则、投资规模、现有网络的问题与不足等;网络系统中所包含的信息点的数量、分布及信息流量、应用程序的类型及对QoS的要求、是否需要提供广域网接入和网络安全上的考虑因素等。需求分析完成后需要提交需求分析调研报告。 2、方案设计 根据需求分析,以层次化的网络设计方法,选择合适的网络技术,设计一个性能价格比相对优化的网络解决方案,网络要提供尽可能高的可靠性、有效性、可扩展性和安全性。设计内容包括、网络拓扑设计、IP寻址模式、路由规划、安全设计、网络管理、服务器相关配置等。 3、方案文档的撰写 撰写一个网络设计方案的书面文档,在该文档中要包括需求分析概述、网络建设的目标与原则、技术选择与技术设计、网络管理与安全、投资预算和设备清单等。 4、说明:完成此部分课程设计,请大家查阅相关资料了解下列网络术语,并尽可能将这些技术应用于你的设计之中;并按实验指导资料,完成校园网模拟配置实验。例如包括: 交换以太网、快速以太网、千兆以太网、VLAN、第三层交换技术、防火墙、无线局域网、DMZ技术等设备技术的选型配置 网络拓扑设计和地址规划等 接入层:交换机堆叠、交换机端口安全、ACL(访问控制列表)、802.1x 汇聚层:链路聚合、动态主机配置 核心层:骨干路由设备、服务器等 出口:NAT、防火墙等
"学 院 "信息科学与工程 "专 业 "电子信息工程 " "学生 " "学 号 " " "设计题目 "校园网络构建方案设计和实现 " " " "容及要求: " "某高校要进行校园网规划,每个院系均有入网信息点,现准备通过科教网接入因" "特网,为了安全,要求每个分校区的学生公寓子网和教师子网不在同一广播域。" "同时,学校有若干台应用服务器,同时对和对外提供Web等网络服务。 " "要求: " "(1)分析以上情况,结合实验室条件,完成需求分析; " "(2)列出所需设备,设计完成网络拓扑结构图; " "(3)在实验环境下完成设备的具体配置; " "(4)调试验证。 " " " "进度安排: " "7月7日 布置题目,安排课程设计任务及相关软件介绍 " "7月8日-7月9日 " "查找相关资料,做出网络规划,画出网络拓扑图,熟悉相关命令 " "7月21日-7月22日 根据拓扑图,配置相关的网络设备,使网络正常运行 " "7月23日 验收 " "7月23日 完成课程设计报告 " "指导教师(签字): "学院院长(签字): " " " " "年 月 日 "年 月 日 " 摘 要 由于计算机与网络技术的特殊性,网络建设需要考虑以下一些因素:系统的先进性、 体统的稳定性、系统的可扩展性、系统的可维护性、应用系统和网络系统的配合度、与 外界网络的连通性、建设成本的可接受度等。 局域网(Local Area Network,LAN)是指传输距离有限,传输速率较高,以共享网络资源为主要目的的网络 系统,它仅包括OSI参考模型的底部3层协议。将一个网络限制在物理上较小的区域之, 可以减少从网络上一台计算机发送数据到最远处计算机的时延。 虚拟局域网功能:VLAN(Virtual Local Area Network,虚拟局域网)是指在交换式局域网的基础上,采用网络管理软件构建的可跨越 不同网段、不同网络的端到端的逻辑网络。一个VLAN组成一个逻辑子网,即一个逻辑广 播域,它可以覆盖多个网络设备,允许处于不同地理位置的网络用户加入到一个逻辑子 网中。同时,在同一台交换机上也可以划分多个VLAN。 关键词:网络 虚拟局域网 交换机 VLAN 目 录 1 课程设计目的&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;1 2 课程设计要求&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;1 3 参考案例&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;1 3.1需求分析&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..1 3.2网络拓扑设计方案&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;2 3.3设备的配置方案&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;.5 3.4.子网的设计方案&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;5 4. 课程设计分析&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;...7 4.1.工作原理&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;.7 4.2.系统拓扑结构&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..9 4.3.划分网段、IP地址与VLAN&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;10 4.设备介绍&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..11 5.设备的配置与验证&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..11 5.1.配置&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..11 5.2.验证&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;..15 6.结果分析&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;...18 7心得体会&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;18 8.参考文献&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;&hellip;...19 校园网络构建方案设计和实现 1.课程设计目的 (1)对计算机网络基本理论知识的加深理解。 (2)通过设计对计算机网络的应用有所了解。 (3)掌握基本cisco基本配置命令并熟练运用。 2.课程设计要求 (1)分析具体情况,结合实验室条件,完成需求分析; (2)列出所需设备,设计完成网络拓扑结构图; (3)在实验环境下完成设备的具体配置; (4)调试验证。 3.参考案例 3.1需求分析 随着信息时代的到来,校园网已经成为现代教育背景下的必要基础设施,成为学校提 高水平的重要途径。能通过与Internet的互联,为全校师生提供国际互联网上的各种服 务。教师可以制作多媒体课件以及在网上保存和查询教学资源,能对学生进行多媒体教 学和通过网络对学生进行指导与考查等。学生也可以通过在网上浏览和查询网上学习资 源,从而可以更好地进行学习,校园网能为学校的信息化建设打下基础。 根据本校园实际情况主要应用需求分析如下: 用户的应用需求:所有用户可以方便地浏览和查询局域网和互联网上的学习资源,通 过WWW服务器、电子服务器、文件服务器、远
### 回答1: tracert和ping是两种常用的网络诊断工具。 tracert(Windows)或traceroute(Linux/Unix)是一种命令行工具,用于查找网络数据包经过的路由器。它通过发送ICMP回显请求和接收ICMP回显应答来实现。每当数据包经过一个路由器时,路由器都会在应答中添加自己的IP地址。tracert收到的应答可以用来构建路由路径的图像。 ping是一种网络诊断工具,用于测试两台计算机之间的网络连通性。它通过发送ICMP回显请求和接收ICMP回显应答来实现。如果目标主机能够收到请求并正确应答,则说明网络连通。 ### 回答2: TRACERT(跟踪路由)和PING(网络包探测器)都是网络诊断工具,在网络故障排除过程中有很好的作用。以下是两者的程序设计实现方式。 TRACERT程序设计实现TRACERT程序的主要功能是确认数据包从源地址(发起机器)到达目标地址(终端机器)所经过的路由器路由路径。以下是TRACERT程序的主要设计与实现: 1. 发送数据包:使用ICMP数据报,发送的数据包TTL(存活时间)为1,目标地址为目标机器IP地址。 2. 接收数据包:同时执行ping操作来接收回传ICMP数据报。 3. 分析路由路径:当数据包弹回到本机时,TRACERT分析ICMP数据报中的路由器IP地址。然后使用相同的方法(含TTL加1)向目标地址发送另一个数据包,并重复这个步骤直到到达目标机器,随后分析整个路由历史记录以得到完整的路由路径。 4. 显示路由路径:将分析得到的路由路径显示出来。 PING程序设计实现PING程序的主要功能是检测目标机器是否可达,以及确认网络时延和丢包率等网络参数。以下是PING程序的主要设计与实现: 1. 发送数据包:使用ICMP数据报,其中有一字段是标识码,另一字段是序列号,这些信息在接收到回声回报后被记录。 2. 接收数据包:当目标机器接收到数据包,立刻发送回答数据包(称为“回声回报”),由源机器接收。 3. 计算时延:PING程序使用RTT(往返时间)来计算往返时延。源机器记录下发送数据包的时刻和接收到回声回报的时刻,然后计算RTT。 4. 显示网络参数:PING程序根据接收到的回声回报,确认网络是否存在丢包现象,并计算丢包率。将计算得到的网络参数显示出来。 总结: TRACERT和PING都是网络故障排除工具,它们的实现方式非常相似。不同之处在于TRACERT主要用于确认路由路径,而PING主要用于测量网络连接的状态。这些工具的设计和实现需要充分理解TCP/IP的基础概念,可以通过深入的网络诊断掌握这些知识点。 ### 回答3: tracert与ping计算机网络中常用的诊断工具,用于检测网络中连接问题以及提供网络连接的质量。这两个工具都可以在Windows、Linux以及其他操作系统中使用,并且都可以通过控制台或命令行启动。 tracert(或traceroute)工具主要用于检测网络中的网络路径和延迟问题。它通过将特殊的IP数据包发送到目标主机,然后在它们传输时,每个网络路由器都记录对应的路由表。这些数据包的“跳数”(即经过多少个路由器)会逐渐增加,直到它们到达目标主机或被时间限制截断。这些记录可以帮助诊断网络中的连接问题,例如路由器断开连接或网络拥塞。 为了实现tracert程序,需要使用一种能够控制IP数据包的协议,例如ICMP(Internet控制消息协议)。该协议可以发送控制信息(例如ping响应)给远程主机,并收集远程主机的响应数据。通过控制这些数据包并检测响应,tracert程序可以记录网络上的所有路由器地址,并计算每个路由器之间的延迟时间。这些信息可以帮助诊断连接问题并优化网络结构。 相比之下,ping工具更为简单,主要用于检测网络上的主机是否可达。该工具发送ICMP回声请求消息到目标主机,并等待目标主机返回相应的回声响应。如果目标主机能够正常响应,则意味着目标主机在线并且网络连接正常。如果收到超时或错误响应,则可能意味着网络存在断开连接或受干扰等问题。 因为ping工具需要发送ICMP数据包并等待目标主机响应,所以实现ping程序需要使用一种能够操作这些数据包的协议,例如ICMP或UDP。程序应该能够在目标主机响应之前设置超时时间,以避免长时间等待响应。同时,应该能够解析远程主机发回的响应消息,以检测连接问题。 综上所述,tracert与ping是网络工程师中必备的网络诊断工具。它们的实现主要涉及操作网络数据包的协议。利用它们可以在网络中检测连接问题以及创建网络结构的优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值