沈 阳 工 程 学 院
学 生 实 验 报 告
实验室名称:信息工程系软件实验室 实验课程名称:计算机网络
实验项目名称:ICMP协议应用——Ping解析 班 级: 姓 名: 学 号:
实验日期:2012年04月28日 实验台编号:23 指导教师:
批阅教师(签字): 成绩:
一.实验目的 1) 掌握ICMP原理,体会网络层编程的不同; 2) 理解ICMP报文的作用,了解基本的网络编程框架。 二.实验内容 1) 解析Ping程序的基本实现过程。 2) 体会ICMP协议在Ping程序中的应用。 3) 体会基本的C/S编程框架。 三.实验前的准备 1) 掌握ICMP原理及相关概念。 2) 掌握C语言编程知识。 3) 掌握基本的网络编程内容 四.实验要求及实验软硬件环境 【基本要求】 对Ping程序进行调试并运行实现。 解析ping程序的主要部分,从而体会ICMP协议的应用。 完成此项实验,完成实验报告。 【实验组织方式】 小组实验 【实验条件】 局域网环境下微机二台,编程软件。 五.实验步骤 1.熟悉IP以及ICMP协议的工作机制; 2.熟悉创建原始套接字、IP报头和ICMP报头; 3.体会ICMP协议的作用与特点; 4.调试ICMP协议的Ping实现程序; 5.参加答辩,并撰写实验报告 六.主要程序部分(C++语言实现) // ping.cpp : 定义控制台应用程序的入口点。 #include struct icmp { unsigned char icmp_type; //类型 unsigned char icmp_code; //编码 unsigned short icmp_chksum; //校验和 unsigned short icmp_id; //标示符 unsigned short icmp_seq; //顺序号 unsigned long icmp_data; //数据 }; struct ip { unsigned char ip_hl:4; //报头长度 unsigned char ip_v:4; //版本号 unsigned char ip_tos; //服务类型 unsigned short ip_len; //总长度 unsigned short ip_id; //标识 unsigned short ip_off; //标志 unsigned char ip_ttl; //生存时间 unsigned char ip_p; //协议号 unsigned short ip_sum; //报头校验和 unsigned long ip_src; //源IP地址 unsigned long ip_dst; //目的IP地址 }; char sendpacket[PACKET_SIZE]; char recvpacket[PACKET_SIZE]; struct sockaddr_in dest_addr; struct sockaddr_in from_addr; int sockfd; int pid; unsigned short cal_chksum(unsigned short *addr,int len); int pack(int pack_no); int unpack(unsigned char *buf,int len); void send_packet(void); void recv_packet(void); int main(int argc, CHAR* argv[]) { struct hostent *host; struct protoent *protocol; int timeout=1000; int SEND_COUNT=4; int i; char *par_host; char m_Input[100]; printf(\"Input IP: \"); gets(m_Input); par_host=m_Input; WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) return; if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { WSACleanup( ); return; } if( (protocol=getprotobyname(\"icmp\") )==NULL) //返回对应于给定协议名的包含名字和协议号 { } if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0) { printf(\"socket error\\n\"); exit(1); printf(\"getprotobyname error\\n\"); //的protoent结构指针 exit(1); } if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout))<0) //设置套接口的选项 fprintf(stderr,\"failed to set recv timeout: %d\\n\ if(setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout))<0) fprintf(stderr,\"failed to set send timeout: %d\\n\ memset(&dest_addr,0,sizeof(dest_addr)); dest_addr.sin_family=AF_INET; if(host=gethostbyname(par_host) ) // 返回对应于给定主机名的主机信息 { memcpy( (char *)&dest_addr.sin_addr,host->h_addr,host->h_length); //resolve address to hostname if(host=gethostbyaddr(host->h_addr,4,PF_INET)) par_host=host->h_name; } else if( dest_addr.sin_addr.s_addr=inet_addr(par_host)==INADDR_NONE) { } printf(\"Unkown host %s\\n\exit(1); pid=_getpid(); printf(\"Pinging %s [%s]: with %d bytes of data:\\n\\n\ for(i=0;i send_packet(); recv_packet(); Sleep(1000); { int packsize; struct icmp *icmp; packsize=8+SEND_SIZE; icmp=(struct icmp*)sendpacket; icmp->icmp_type=ICMP_ECHO; icmp->icmp_code=0; icmp->icmp_chksum=0; icmp->icmp_seq=pack_no; icmp->icmp_id=pid; icmp->icmp_data=GetTickCount(); icmp->icmp_chksum=cal_chksum( (unsigned short *)icmp,packsize); /*校验算法*/ return packsize; } //解包 int unpack(char *buf,int len) { struct ip *ip; struct icmp *icmp; double rtt; int iphdrlen; ip=(struct ip *)buf; iphdrlen=ip->ip_hl*4; icmp=(struct icmp *)(buf+iphdrlen); if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) ) { len=len-iphdrlen-8; rtt=GetTickCount()-icmp->icmp_data; printf(\"Reply from %s: bytes=%d time=%.0fms TTL=%d icmp_seq=%u\\n\ inet_ntoa(from_addr.sin_addr), len, rtt, ip->ip_ttl, icmp->icmp_seq); return 1; } return 0; } //发送 void send_packet() { int packetsize; static int pack_no=0; packetsize=pack(pack_no++); if( sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0 ) printf(\"Destination host unreachable.\\n\"); // printf(\"send NO %d\\n\} //接收 void recv_packet() { int n,fromlen; int success; fromlen=sizeof(from_addr); do { if( (n=recvfrom(sockfd,recvpacket,sizeof(recvpacket),0,(struct sockaddr *)&from_addr,&fromlen)) >=0) success=unpack(recvpacket,n); else if (WSAGetLastError() == WSAETIMEDOUT) { printf(\"Request timed out.\\n\"); return; } }while(!success); } 七.结果分析 运行结果如图1所示: 图1 运行结果 运行结果可看出此程序不断地在向172.20.72.12发送数据包,并且得到了应答。 八.个人总结 本次课程设计较好地实现了要求做到的功能,但同时也遇到不少的困难和挑战。通过本次实验我们了解到 ICMP协议是一个非常重要的协议,它对于网络安全、网络的正常运作具有极其重要的意义,它被用于在IP主机、路由器之间传递控制消息,如网络通不通、主机是否可达、路由是否可用等。实验中将原始数据在网络层添加IP报头和数据链路层添加ICMP的报头,再在目的端解封装这两个报头。通过这次实验,我们不但加深了对Socket的原始套接字RAW编程的理解,同时也对IP和ICMP协议有了进一步的认识。 教 师 评 语 教师签字: 年 月 日 因篇幅问题不能全部显示,请点此查看更多更全内容