计算机网络实验之Ping程序的设计与实现
- 格式:doc
- 大小:713.24 KB
- 文档页数:13
Ping程序的设计与实现Ping的基本实现原理请参考以下文档:/view/e0769dc69ec3d5bbfd0a7476.html;/view/9ee3583143323968011c9213.html;初学者读代码请先百度:socket(),setsockopt(),HeapAlloc()等函数。
使用说明:1、找到\Debug\ping.exe (即生成的可执行文件的目录);(Ping是工程名)2、开始->运行->cmd进入命令提示符模式;3、cd \Debug\ping.exe;然后输入参数即可。
Ping程序源码(无注释)//Ping.h#define WIN32_LEAN_AND_MEAN#include<windows.h>#include<winsock2.h>#include<ws2tcpip.h>#include<stdio.h>#include<stdlib.h>typedef struct tagIP_HEADER{unsigned int h_len:4;unsigned int ver:4;unsigned char tos;unsigned short total_len;unsigned short ident;unsigned short frag_floags;unsigned char ttl;unsigned char protocol;unsigned short checksum;unsigned int sourceip;unsigned int destip;}IP_HEADER,*PIP_HEADER;typedef struct tagIP_OPT_HEADER{unsigned char code;unsigned char len;unsigned char ptr;unsigned long addr[9];}IP_OPT_HEADER,*PIP_OPT_HEADER;typedef struct tagICMP_HEADER{unsigned char type;unsigned char code;unsigned short checksum;unsigned short id;unsigned short seq;unsigned long timestamp;}ICMP_HEADER,*PICMP_HEADER;#define DEF_PACKET_SIZE 32#define MAX_PACKET_SIZE 1024#define ICMP_ECHO 8#define ICMP_ECHOREPL Y 0#define IP_RECORD_ROUTER 7void usageinfo(char *progname);void FillIcmpData(char *icmp_data,int size);USHORT CheckSum(USHORT *buf,int size);void DecodeIcmpHeader(char *buf,int ret,LPSOCKADDR_IN lpSin); void DecodeIpHeader(char *buf,int bytes);//Ping.cpp#include<stdio.h>#include"Ping.h"#pragma comment(lib,"ws2_32")int main(int argc,char *argv[]){if(argc==1){usageinfo(argv[0]);return -1;}BOOL bRecordRout =FALSE;SOCKET hSocket =INV ALID_SOCKET;SOCKADDR_IN dstSin;SOCKADDR_IN fromSin;IP_OPT_HEADER ipOptHeader;char* pIcmpData = NULL;char* pRecvData = NULL;char* lpDstIp =NULL;int datasize =DEF_PACKET_SIZE;int ret;int rcvNum;for(int i=1;i<argc;i++){if(strchr(argv[i],'-')){switch(tolower(argv[i][1])){case 'r':bRecordRout=TRUE;break;case 'd':datasize=atoi(argv[i+1]);i=argc+1;break;}}else if(strchr(argv[i],'.')){int l=strlen(argv[i]);if(l<7||l>15)usageinfo(argv[0]);elselpDstIp=argv[i];}}WSADATA wsaData;WORD wVer=MAKEWORD(2,2);if(WSAStartup(wVer,&wsaData)!=0){printf("WSAStartup Error!\n");return -1;}hSocket=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);if(hSocket==INV ALID_SOCKET){printf("WSASocket Error,Code:%d",WSAGetLastError());WSACleanup();return -1;}if(bRecordRout){ZeroMemory(&ipOptHeader,sizeof(ipOptHeader));ipOptHeader.code=IP_RECORD_ROUTER;ipOptHeader.len=39;ipOptHeader.ptr=4;if((ret=setsockopt(hSocket,IPPROTO_IP,IP_OPTIONS,(char*)&ipOptHeader,sizeof(ipOptH eader)))==SOCKET_ERROR){printf("setsockopt(IP_OPTIONS)error,code:%d",WSAGetLastError());WSACleanup();closesocket(hSocket);return -1;}}int timeout=1000;if((ret=setsockopt(hSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout )))==SOCKET_ERROR){printf("setsockopt(SO_RCVTIMEO)error,code:%d",WSAGetLastError());WSACleanup();closesocket(hSocket);return -1;}if((ret=setsockopt(hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout )))==SOCKET_ERROR){printf("setsockopt(SO_SNDTIMEO)error,code:%d",WSAGetLastError());WSACleanup();return -1;}pIcmpData=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET _SIZE);pRecvData=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET _SIZE);if(pIcmpData==NULL||pRecvData==NULL){printf("HeapAlloc Error\n");WSACleanup();return -1;}datasize+=sizeof(ICMP_HEADER);ZeroMemory(&dstSin,sizeof(dstSin));dstSin.sin_family=AF_INET;dstSin.sin_addr.s_addr =inet_addr(lpDstIp);FillIcmpData(pIcmpData,datasize);printf("Ping %s with %d bytes of data\n",inet_ntoa(dstSin.sin_addr),datasize);int count=0;int seq=0;rcvNum=0;while(1){count++;if(count==5)break;((PICMP_HEADER)pIcmpData)->checksum=0;((PICMP_HEADER)pIcmpData)->seq=seq++;((PICMP_HEADER)pIcmpData)->timestamp=GetTickCount();((PICMP_HEADER)pIcmpData)->checksum=CheckSum((USHORT*)pIcmpData,datasize);if((ret=sendto(hSocket,pIcmpData,datasize,0,(LPSOCKADDR)&dstSin,sizeof(dstSin)))==S OCKET_ERROR){if(WSAGetLastError()==WSAETIMEDOUT){printf("time out.\n");continue;}else{printf("sendto error,code:%d",WSAGetLastError());closesocket(hSocket);WSACleanup();return -1;}}int fromLen=sizeof(fromSin);if((ret=recvfrom(hSocket,pRecvData,MAX_PACKET_SIZE,0,(sockaddr*)&fromSin,&from Len))==SOCKET_ERROR){if(WSAGetLastError()==WSAETIMEDOUT){printf("time out.\n");continue;}printf("recvform fail!\n");closesocket(hSocket);WSACleanup();return -1;}rcvNum++;DecodeIcmpHeader(pRecvData,ret,&fromSin);}printf("\n Ping Statistics for :%s\n",lpDstIp);printf("\t Send=%d Received=%d,Lost=%d(%d%%loss)",4,rcvNum,4-rcvNum,(4-rcvNum)/4*100);if(hSocket!=INV ALID_SOCKET)closesocket(hSocket);HeapFree(GetProcessHeap(),0,pIcmpData);HeapFree(GetProcessHeap(),0,pRecvData);WSACleanup();return 0;}void usageinfo(char *progname){printf("Pingtool,byblode(********************.cn\n)");printf("usage:ping[-r]<host ip>[-d][data size]\n");printf("\t-r:\trecord router\n");printf("\thost ip:\thost ip to ping\n");printf("\t-d:\tuse data size option\n");printf("\tdata size:\tdata size to ping(<=1024)\n");}void FillIcmpData(char *icmp_data,int size){ICMP_HEADER *icmpHdr;icmpHdr=(PICMP_HEADER)icmp_data;icmpHdr->checksum=0;icmpHdr->code=0;icmpHdr->id=(unsigned short)GetCurrentProcessId();icmpHdr->seq=0;icmpHdr->type=ICMP_ECHO;icmpHdr->timestamp=0;}USHORT CheckSum(USHORT *buf,int size){USHORT cksum=0;while(size>1){cksum+=*buf++;size-=sizeof(USHORT);}if(size)cksum+=*buf++;cksum=(cksum>>16)+(cksum&0xffff);cksum+=(cksum>>16);return (USHORT)(~cksum);}void DecodeIcmpHeader(char *buf,int ret,LPSOCKADDR_IN lpSin) {ICMP_HEADER *icmpHdr;IP_HEADER *ipHdr;int ipHdrLen;static int first=0;DWORD tick=GetTickCount();ipHdr=(IP_HEADER*)buf;ipHdrLen=ipHdr->h_len*4;if(ipHdrLen==60&&!first)DecodeIpHeader(buf,ret);icmpHdr=(ICMP_HEADER *)(buf+ipHdrLen);if(icmpHdr->type!=ICMP_ECHOREPL Y){printf("no echo reply %d recved\n",icmpHdr->type);return ;}if(icmpHdr->id!=(USHORT)GetCurrentProcessId()){printf("someone else's packet!\n");return;}printf("Reply form: %s",inet_ntoa(lpSin->sin_addr));printf("\tbytes: %d icmp seq: %d TTL=128",ret,icmpHdr->seq);printf("time: %dms\n",tick-icmpHdr->timestamp);first++;return;}void DecodeIpHeader(char *buf,int bytes){IP_OPT_HEADER *ipOptHdr;IN_ADDR in;ipOptHdr=(IP_OPT_HEADER *)(buf+20);printf("Record Router:");for(int i=0;i<(ipOptHdr->ptr/4)-1;i++){in.S_un.S_addr=ipOptHdr->addr[i];printf("\t%-15s\n",inet_ntoa(in));}}。
〖实验项目名称〗:计算机网络基础〖实验目的〗:1、熟悉网卡、掌握如何在Windows下如何察看网卡的型号、MAC地址、IP地址等参数。
2、熟悉Windows中的网络组建及各参数的设置和基本意义。
3、网络测试命令PING的用法。
〖实验任务与要求〗:1、网卡是网络中不可缺少的网络设备,掌握其使用情况,及如何设置其参数对网络的正常使用非常重要。
本部分要完成以下任务:(1)利用Windows下ipconfig 命令查看网卡的基本参数。
(2)如何设置网卡的IP地址。
2、Ping是个使用频率极高的实用程序,用于确定本地主机是否能与另一台主机交换(发送与接收)数据报。
根据返回的信息,就可以推断TCP/IP参数是否设置得正确以及运行是否正常。
(1)Ping 本机IP(Ping 本机机器名;Ping 127.0.0.1)。
(2)Ping 邻近计算机的IP(或者是对方计算机的机器名)。
(3)Ping 网站(前题是能接入Internet)。
〖实验过程〗:(实验步骤、记录、数据、分析)1.Ipconfig的使用(1)、开始-运行,在弹出的对框框中,输入CMD将进入黑白屏幕的DOS界面。
(2)、在“命令提示符”下输入ipconfig/all查看本机网卡的基本参数。
(2)利用“网上邻居”修改网络参数。
(3)PING命令的使用ping 127.0.0.1ping 本机IPping localhostping 局域网内其他IP PING命令参数:-n:发送count指定的ECHO数据包数,通过这个命令可以自己定义发送的个数,对衡量网络速度很有帮助。
能够测试发送数据包的返回平均时间,及时间的快慢程度。
默认值为 4。
-r:在“记录路由”字段中记录传出和返回数据包的路由。
通常情况下,发送的数据包是通过一系列路由才到达目标地址的,通过此参数可以设定,想探测经过路由的个数。
限定能跟踪到9个路由。
一般情况下,通过ping目标地址,可让对方返回TTL值的大小,通过TTL值可以粗略判断目标主机的系统类型是Windows还是UNIX/Linux,一般情况下Windows系统返回的TTL值在100-130之间,而UNIX/Linux系统返回的TTL值在240-255之间。
计算机网络课程设计Ping程序设计(后附源码)四川大学黄昊1143041195一.设计目标二.ICMP包结构三.校验和计算四.代码实现a)ICMP封包b)ICMP包转换成字节数组c)域名解析、选择IPv4地址d)原始套接口e)计算校验和五.运行结果六.总结一、设计目标本程序设计实现基本的ping程序功能,包括域名解析,ICMPv4回显包发送,统计丢失率等功能。
二、ICMP包结构ICMP包包含在IP包结构之内,是去除IP包头的部分,C#提供的Raw Socket功能可以实现包装ICMP结构,但自动包含IP包头等结构。
ICMP包由1Byte类型、1Byte SubCode、2字节校验和、2字节标示符、2字节序号,若干字节数据组成。
其结构图如下:4Byte类型号8 、子代码表示ICMP回显功能,默认标示符45、序号0、Data小节可填充数据,本程序填充了ASCII码‘a’十六进制61,填充24字节,所以整个包大小共32字节。
三、校验和计算对于ICMP包中的校验和,首先将校验和填0之后再整体计算。
计算时,按照2字节为一个单位累加,最后将所有溢出结果再次做加法,最后整体取反,返回一个2字节长的校验和。
具体计算方法伪代码如下:Int32 cksum = 0;for (int i = 0; i < 16; i++){cksum += ConvertToUInt16(packet, i * 2);}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >> 16);return (ushort)(~cksum);四、代码实现a)实现难度1:封装ICMP包。
为了方便操作与计算,在C#中,创建了一个ICMP包的结构体。
为了使包的逻辑结构与实际发送的结构一样,借助了C#提供的一个机制,叫非托管内存布局,使用StructLayoutAttribute属性,其中参数LayoutKind.Sequential指定了整个结构体的数据堆放方式为顺序堆放,保证内存中数据的连续性。
ping程序设计与实现课程设计一、课程目标知识目标:1. 学生能理解ping程序的工作原理,掌握网络诊断的基本方法。
2. 学生能描述IP协议、ICMP协议的基本概念及其在ping程序中的应用。
3. 学生了解计算机网络的通信原理,掌握如何利用ping程序检测网络连通性。
技能目标:1. 学生能运用所学知识,独立编写简单的ping程序。
2. 学生通过实践操作,提高问题分析及解决能力,具备基本的网络诊断技巧。
3. 学生掌握使用编程工具(如:IDE、编译器等)进行代码编写、调试和优化。
情感态度价值观目标:1. 学生培养对计算机网络的兴趣,激发学习编程的热情。
2. 学生在学习过程中,培养团队协作、沟通表达的能力,增强自信心。
3. 学生通过本课程的学习,认识到网络技术在实际应用中的重要性,培养对网络安全的责任感。
分析课程性质、学生特点和教学要求,本课程旨在让学生掌握ping程序的设计与实现,结合实际操作,提高学生的编程能力和网络诊断技巧。
课程目标具体、可衡量,有助于教师进行教学设计和评估。
通过本课程的学习,学生将具备基本的网络编程知识和技能,为今后的学习和工作打下坚实基础。
二、教学内容1. 网络基础知识回顾:IP协议、ICMP协议、网络层通信原理。
2. ping程序工作原理:发送ICMP请求、接收ICMP回复、计算往返时间(RTT)。
3. 编程语言基础:C语言或Python语言的基本语法,重点掌握数据类型、控制结构、函数定义。
4. ping程序设计与实现:- 环境搭建:安装编程工具、配置网络环境。
- 代码编写:根据ping程序工作原理,编写发送和接收ICMP请求的代码。
- 调试与优化:调试代码,处理异常情况,优化程序性能。
5. 实践操作:分组进行实际操作,组内讨论、分析问题,相互协作完成ping 程序编写。
6. 网络诊断技巧:运用ping程序检测网络连通性,分析网络延迟、丢包等问题。
教学内容安排和进度:第一课时:网络基础知识回顾,介绍ping程序工作原理。
课程名称计算机网络实验序号实验五实验项目Ping程序的设计与实现2017年03月25 日实验报告要求1、实验报告封面填表说明(每份实验报告必须附上封面)(1)课程名称:要求与实验大纲和实验指导书中的课程名称一致。
(2)实验序号:指该课程的第几个实验。
(3)实验项目:要求与实验大纲和实验指导书中的实验项目一致。
(4)实验地点:填写完成该实验项目所在的实验室名称。
(5)实验学时:要求与实验大纲和实验指导书中完成该实验项目所需学时一致。
(6)实验类型:是指演示性、操作性、验证性、综合性、设计性。
演示性:教师操作,学生观察,验证理论、说明原理和方法。
操作性:学生按要求动手拆装、调试实验装置或上机操作,掌握其基本原理和方法。
验证性:按实验指导书(教材)要求,由学生通过操作验证所学理论,加深对理论、知识的理解,掌握基本实验知识、方法、技能、数据处理等。
综合性:实验内容涉及本课程的综合知识或相关课程的知识,运用多的知识、多种方法,按要求或自拟实验方案进行实验。
主要培养学生综合运用所学知识、实验方法和实验技能,以培养其分析、解决问题的能力。
设计性:给定实验目的、要求和实验条件,学生自己设计实验方案并加以实现的实验。
学生独立完成从查阅资料、拟定实验方案、实验方法和步骤(或系统分析和设计)、选择仪器设备(或自行设计缺制作)进行实验并完成实验全过程,形成实验报告,培养学生自主实验的能力。
(1)批改:全部批改及更正错误。
(2)评分:按百分制评分,不能评分为“优、良、中、差”或“A、B、C”。
(3)签名及批改日期:任课教师必须在每份学生实验报告中签名和写上批改日期。
(4)成绩:填写学生实验成绩表,实验成绩作为考试成绩评定的依据。
(4)评语:任课教师批改学生实验报告时,应给出简明扼要的评语。
二、实验原理与内容1、一种网络诊断工具2、发送ICMP回送请求报文3、接收 ICMP回送应答报文4、 IP报文格式5、WinSock原始套接字的使用方法与API函数W insock原始套接字编程过程中,服务器端/客户端的编程都按照以下步骤:初始化套接字(WSAStartup)创建套接字(socket或WSASocket)向服务器通信(sendto/recvfrom)关闭套接字(closesocket)结束使用套接字(WSACleanup)6、三种WinSock地址结构①用的Winsock地址结构sockaddr ,针对各种通信域的套接字,存储它们的地址4.编写各个函数代码块5.编译,运行实验代码如下:(温馨提醒:意要在.cpp文件的前后添加#include"stdafx.h" (是预编译处理器把stdafx.h文件中的内容加载到程序中来。
设计报告课程计算机网络设计名称《ping命令的设计与实现》专业班级计科094 同组人姓名同组人学号实验日期2013-04-10 指导教师成绩2013 年 04 月 10 日设计目的和要求1、实验目的:Ping命令向目的主机发送ICMP ECHO—REQUEST请求并接收目的主机返回的响应报文,用来检验本地主机和远程的主机是否连接。
2.实验要求:利用ICMP数据包,测试主机的连通性,通过课程设计,使学生熟悉ICMP报文结构,使学生对ICMP有更深的理解。
要求:输出参考系统自带ping程序,命令行运行:ping ip二、设计说明设计分析:使用原始套接字可以读写ICMP分组,利用原始套接字发送ICMP回显请求,并接收ICMP 回显应答,通过icmp_send()发送ICMP回显示请求包,icmp_recv()接收ping目的主机的回复,并使用终端信号处理函数SIGINT处理信号,建立两个线程,一个用于发送数据,另一个用于接收响应数据,主程序等待两个线程运行完毕后再进行下一步动作。
最后,主程序讲发送数据和接收的数据进行统计,并将结果打印出来。
系统运行环境:虚拟机:Fedora14(linux操作系统) gcc设计中的重点和难点:ICMP数据包的打包和解包,以及从CRC16校验算法的分析实现输入和输出条件:在linux系统下运行ping 在出现4个响应包后按Ctrl+c键停止发送。
三、系统详细设计《Ping命令的设计与实现》Ping命令向目的主机发送ICMP ECHO—REQUEST请求并接收目的主机返回的响应报文,用来检验本地主机和远程的主机是否连接。
协议格式图1.1中已经对ICMP协议的报文格式进行了说明。
Ping 的客户端方式的类型为8,代码值为0,表示ICMP的回显请求。
类型为0,代码为0是,是ICMP回显应答。
检验和为16为的crc16 的算法。
0 7 8 15 16 31图1.1 ICMP报文的数据格式图1.2所示为ping所使用的类型和代码格式。
ping程序的设计与实现
Ping程序的设计与实现是通过一种单向测量技术来实现的,它可以用来评估网络的性能、访问故障和网络可用性。
Ping程序工作时会首先向目标主机发送一个ICMP(网际控制报文协议)报文,然后等待目标主机的应答。
在实现ping程序的过程中,首先要为发送的ICMP数据报定义一个数据结构,这个数据结构将包含所有必要的信息,如报文类型、报文代码、校验和等。
其次,要实现函数,对这个数据结构进行填充和序列化,以便将ICMP报文发送出去。
实现发送ICMP报文后,就要开始接收应答。
为此,可以利用Socket API来创建一个Raw Socket,以便从网络上接收ICMP报文,并将其解码为数据结构,以便能够识别是哪一条报文的应答。
最后,还需要实现超时,用来处理因网络拥塞或丢包等原因导致的应答报文没有收到的情况。
这可以通过在发送ICMP报文之前先设置一个定时器,当定时器到期时,就可以判断该报文没有收到应答报文而超时。
以上就是ping程序的大致设计与实现方式,整个实现的过程可以大体分为发送ICMP数据报、接收应答和超时处理三部分。
这些都需要对数据报结构进行定义和填充,以及使用Socket API创建Raw Socket 来发送和接收数据,并通过设置定时器来实现超时处理,以保证ping 程序可以正常工作。
遵义师范学院计算机和信息科学学院实验报告(2012—2013学年第一学期)课程名称:网络安全实验班级:计科一班学号:10410901036姓名:陈志军任课教师:蒲晓川计算机和信息科学学院《网络安全扫描》实验报告实验名称实验6-1 Ping主机扫描实验指导教师蒲晓川网络安全防实验类型实验学时 2 实验时间11.29范一、实验目的和要求1.了解和学习Ping命令扫描实现的基本原理。
2.学习和掌握Windows Ping命令的操作使用及其在主机扫描中的使用。
3.学习和掌握Ping扫描子网主机。
二、实验仪器和器材计算机一台Vmware虚拟机三、实验内容及步骤1、Windows Ping命令重要参数使用。
(1)设置发送Ping 探测报文的数量,发送ICMP报文数据包,检测当前网络状况,如图1.1所示:(2)连续发送ICMP探测报文1、通过使用“-t”参数实现连续发送ICMP探测报文。
如图1.2所示:图1.2 连续发送ICMP探测报文2、使用Ctrl+Break命令,查看ping统计信息。
如图1.3所示:图1.3 用Ctrl+Break命令查看ping统计信息3、使用Ctrl+C命令,可以结束发送ICMP Echo Request报文。
如图1.4所示:(3)配置Ping探测报文的TTL值,发送TTL值为1的ICMP报文。
如图1.5所示:(4)配置Ping探测报文大小。
如图1.6所示:(5)禁止对Ping探测报文分片。
如图1.7所示:(6)设置Ping命令的请求超时时间。
Ping命令的默认回应时间是1000毫秒,用“-w 时间值”参数可以修改回应时间。
如图1.8所示:图1.8设置Ping命令的超时等待时间2、利用Ping命令进行主机扫描(1)扫描内部实验网的目标主机。
如图2.1所示:图2.1 Ping目标主机扫描结果(2)、Ping外网测试。
如图2.2所示:图2.2 Ping师院教务处网站、(3)、Ping域名。
计算机网络课程设计报告设计名称 Ping程序的设计与实现专业班级同组人姓名指导教师成绩一、设计目的和要求1、实验目的利用ICMP数据包、C语言实现Ping命令程序,能实现基本的Ping操作,发送ICMP回显请求报文,用于测试—个主机到只一个主机之间的连通情况。
通过本程序的训练,使学生熟悉ICMP报文结构,使学生对ICMP有更深的理解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
2、实验要求:输出参考系统自带ping程序,命令行运行:ping ip;二、设计说明1.设计思路由于Ping程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。
为了实现直接对IP和ICMP包进行操作,实验中使用RA W模式的socket编程。
首先定义IP数据报首部,在IP数据报的基础上定义ICMP数据报首部,并初始化一些全局变量。
接着自定义填充ICMP数据报字段函数FillICMPData()、校验和函数checksum()、解读ICMP报首部函数DecodeICMPHeader()、释放资源函Cleanup()。
最后主函数通过调用这些函数来实现Ping命令功能。
2.设计方案IP头与ICMP头的设置分别参照RFC791及RFC792的标准,包含所有必要信息。
主程序设置main()函数,主函数用库函数实现套接字编程用于数据包发送及接收,其中,数据包发送调用sendto(),数据包接收调用recvfrom( ),由于发送数据包时可能会遇到阻塞或者目标主机不通,造成超时,因此需要在发送数据包后调用一个函数判断是否超时,此处调用库函数setsockopt()来实现超时判断;其次,校验和函数采用移位方法进行计算。
3. 系统运行环境:VC++ 6.0,Window XP操作系统平台4. 设计中的难点和重点首先遇到的问题就是套接字文件的问题。
套接字所需要的文件有头文件Winsocket2.h、库文件WS2_32.LIB、动态库W32_32.DLL。
课程名称计算机网络实验序号实验五实验项目 Ping程序的设计与实现2017年 03月 25 日实验报告要求1、实验报告封面填表说明(每份实验报告必须附上封面)(1)课程名称:要求与实验大纲和实验指导书中的课程名称一致。
(2)实验序号:指该课程的第几个实验。
(3)实验项目:要求与实验大纲和实验指导书中的实验项目一致。
(4)实验地点:填写完成该实验项目所在的实验室名称。
(5)实验学时:要求与实验大纲和实验指导书中完成该实验项目所需学时一致。
(6)实验类型:是指演示性、操作性、验证性、综合性、设计性。
演示性:教师操作,学生观察,验证理论、说明原理和方法。
操作性:学生按要求动手拆装、调试实验装置或上机操作,掌握其基本原理和方法。
验证性:按实验指导书(教材)要求,由学生通过操作验证所学理论,加深对理论、知识的理解,掌握基本实验知识、方法、技能、数据处理等。
综合性:实验容涉及本课程的综合知识或相关课程的知识,运用多的知识、多种方法,按要求或自拟实验方案进行实验。
主要培养学生综合运用所学知识、实验方法和实验技能,以培养其分析、解决问题的能力。
设计性:给定实验目的、要求和实验条件,学生自己设计实验方案并加以实现的实验。
学生独立完成从查阅资料、拟定实验方案、实验方法和步骤(或系统分析和设计)、选择仪器设备(或自行设计缺制作)进行实验并完成实验全过程,形成实验报告,培养学生自主实验的能力。
3、教师批改学生实验报告要求(1)批改:全部批改及更正错误。
(2)评分:按百分制评分,不能评分为“优、良、中、差”或“A、B、C”。
(3)签名及批改日期:任课教师必须在每份学生实验报告中签名和写上批改日期。
(4)成绩:填写学生实验成绩表,实验成绩作为考试成绩评定的依据。
(4)评语:任课教师批改学生实验报告时,应给出简明扼要的评语。
二、实验原理与容1、一种网络诊断工具2、发送ICMP回送请求报文3、接收 ICMP回送应答报文4、 IP报文格式5、WinSock原始套接字的使用方法与API函数W insock原始套接字编程过程中,服务器端/客户端的编程都按照以下步骤:初始化套接字(WSAStartup)创建套接字(socket或WSASocket)向服务器通信(sendto/recvfrom)关闭套接字(closesocket)结束使用套接字(WSACleanup)6、三种WinSock地址结构①用的Winsock地址结构sockaddr ,针对各种通信域的套接字,存储它们的地址4.编写各个函数代码块5.编译,运行实验代码如下:(温馨提醒:意要在.cpp文件的前后添加#include"stdafx.h" (是预编译处理器把stdafx.h文件中的容加载到程序中来。
))#include"stdafx.h"#pragma pack(4)#pragma comment( lib, "ws2_32.lib" )#include"winsock2.h"//#include "stdafx.h"//增加的头文#include"stdlib.h"#include"stdio.h"#define ICMP_ECHO 8 // ICMP ECHO 请求报文类型#define ICMP_ECHOREPLY 0 // ICMP ECHO 响应报文类型#define ICMP_MIN 8 // 最小ICMP报文大小为8 bytes (只有ICMP首部)#define ICMP_PACKET_SIZE 32 //ICMP报文数据大小#define ICMP_PACKET_NUMBER 4 //发送ICMP报文的个数#define MAX_PACKET 1024 // 最大ICMP报文数据长度#define ICMP_TIMEOUT 1000 //ICMP超时时间#define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))#define xfree(p) HeapFree (GetProcessHeap(),0,(p))/* 定义结构体:IP 首部*/typedef struct iphdr {unsigned int h_len : 4; // 首部长度unsigned int version : 4; // IP版本unsigned char tos; // 服务类型unsigned short total_len; // 报文总长度unsigned short ident; // IP报文标识符unsigned short frag_and_flags; // 分片标记和片偏移unsigned char ttl; // 生存时间unsigned char proto; // 报文数据的协议类型unsigned short checksum; // 首部检验和unsigned int sourceIP; // 源IPunsigned int destIP; // 目的IP}IpHeader;/* 定义结构体:ICMP 首部*/typedef struct icmphdr {BYTE i_type; // ICMP报文类型BYTE i_code; // 代码USHORT i_cksum; // 报文校验和USHORT i_id; // ICMP报文标识符USHORT i_seq; // 报文序号ULONG timestamp; //时间戳,不是ICMP报文首部的标准组成部分}IcmpHeader;void fill_icmp_data(char *, int); // ICMP请求报文填充函数USHORT checksum(USHORT *, int); // 校验和计算函数int decode_resp(char *, int, struct sockaddr_in *); // ICMP应答报文解析函数int main(int argc, char **argv){WSADATA wsaData; //套接字信息SOCKET sockRaw; //原始套件字char dest_ip[16];//目的IP(字符串)unsigned int addr = 0; //目的IP(整型)struct sockaddr_in dest; //目的IP(sockaddr_in结构)struct sockaddr_in from; //源socket地址int fromlen = sizeof(from);//源socket地址的长度int datasize; //报文总长度(=首部大小+数据大小)//int bwrote, bread; //实际发送和接收数据大小int timeout = ICMP_TIMEOUT; //超时时间USHORT seq_no = 0;//报文序号从0开始递增int statistic = 0; // 成功接收报文的个数char *icmp_data; //指向发送缓冲区的指针char *recvbuf; //指向接收缓冲区的指针memset(dest_ip, '\0', sizeof(dest_ip));if (argc<2) {printf("Please input destination host IP(请输入目的IP):");scanf("%s", &dest_ip);}elsememcpy(dest_ip, argv[1], strlen(argv[1]));/* 初始化函数 */if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){//第一处printf("WSAStartup failed: %d\n", GetLastError());return -1;}/* 创建传输ICMP协议数据的原始套接字 */sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);//第二/* raw-protocol interface */第三处if (sockRaw == INVALID_SOCKET) {printf("WSASocket() failed: %d\n", WSAGetLastError());return -1;}/* 设置套接字的接收超时选项(即设置SO_RCVTIMEO) */if (setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR){printf("failed to set recv timeout: %d\n", WSAGetLastError());return -1;}/* 设置套接字的发送超时选项(即设置SO_SNDTIMEO) */if (setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) == SOCKET_ERROR){printf("failed to set send timeout: %d\n", WSAGetLastError());return -1;}/* 转换指定的目的IP为winsocket地址结构*/addr = inet_addr(dest_ip);//第四处inet_addr()的功能是将一个点分十进制的IP转换成一个长整数型数(u_long类型)dest.sin_addr.s_addr = addr;dest.sin_family = AF_INET;/* 创建发送缓冲区,分配存*/datasize = ICMP_PACKET_SIZE + sizeof(IcmpHeader);icmp_data = (char*)xmalloc(MAX_PACKET);if (!icmp_data) {printf("HeapAlloc failed %d\n", GetLastError());return -1;}/* 创建接收缓冲区,分配存*/recvbuf = (char*)xmalloc(MAX_PACKET);if (!recvbuf) {printf("HeapAlloc failed %d\n", GetLastError());return -1;}/* 填充待发送的ICMP请求报文*/memset(icmp_data, 0, MAX_PACKET);fill_icmp_data(icmp_data, datasize);/* 显示ping提示信息*/printf("\nPinging %s ....\n\n", dest_ip);/* 发送4个ICMP请求报文,并接收应答报文*/for (int i = 0; i<ICMP_PACKET_NUMBER; i++){int bwrote = 0, bread = 0; //实际发送和接收数据大小((IcmpHeader*)icmp_data)->i_cksum = 0; //校验和字段置0((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); //时间戳字段置为当前系统时间((IcmpHeader*)icmp_data)->i_seq = seq_no++; //序号字段每次递增1((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);//计算校验和/* 发送ICMP请求报文*/bwrote = sendto(sockRaw, icmp_data, datasize, 0, (struct sockaddr*)&dest, sizeof(dest));//第五第六处if (bwrote == SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT) {printf("Request timed out.\n");continue;}printf("sendto failed: %d\n", WSAGetLastError());return -1;}/* 接收ICMP应答报文*/bread = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0, (struct sockaddr*)&from, &fromlen);//第七处if (bread == SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT) {printf("Request timed out.\n");continue;}printf("recvfrom failed: %d\n", WSAGetLastError());return -1;}/* 如果解析成功,递增成功接收的数目++ */if (!decode_resp(recvbuf, bread, &from))statistic++;Sleep(1000); //间隔1000ms后再发下一个请求报文}/* 显示用户名和统计结果*/printf("\nPing statistics collected by XXX for %s \n", dest_ip);printf(" Packets: Sent = %d,Received = %d, Lost = %d (%2.0f%% loss)\n",ICMP_PACKET_NUMBER, //发送报文个数statistic,//接收报文个数(ICMP_PACKET_NUMBER - statistic),//丢失报文个数(float)(ICMP_PACKET_NUMBER - statistic) / ICMP_PACKET_NUMBER * 100);//丢包率/* 关闭套接字 */closesocket(sockRaw);//第九处/* 注销函数 */WSACleanup();return 0;}/* ICMP回送请求报文填充函数 */void fill_icmp_data(char * icmp_data, int datasize){IcmpHeader *icmp_hdr;char *datapart;icmp_hdr = (IcmpHeader*)icmp_data;icmp_hdr->i_type = ICMP_ECHO;icmp_hdr->i_code = 0;icmp_hdr->i_id = (USHORT)GetCurrentProcessId();icmp_hdr->i_cksum = 0;icmp_hdr->i_seq = 0;datapart = icmp_data + sizeof(IcmpHeader);memset(datapart, 'E', datasize - sizeof(IcmpHeader));}/* ICMP回送应答报文解析函数 */int decode_resp(char *buf, int bytes, struct sockaddr_in *from){IpHeader *iphdr;IcmpHeader *icmphdr;unsigned short iphdrlen;iphdr = (IpHeader *)buf;iphdrlen = (iphdr->h_len) * 4;if (bytes < iphdrlen + ICMP_MIN) {printf("Too few bytes from %s\n", inet_ntoa(from->sin_addr));return -1;}icmphdr = (IcmpHeader*)(buf + iphdrlen);if (icmphdr->i_type != ICMP_ECHOREPLY) {printf("non-echo type %d recvd\n", icmphdr->i_type);return -1;}if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {printf("someone else''s packet!\n");return -1;}printf("%d bytes from %s:", bytes- iphdrlen - sizeof(IcmpHeader), inet_ntoa(from->sin_addr));printf(" icmp_seq = %d. ", icmphdr->i_seq);printf(" time: %d ms ", bytes);printf("\n");return 0;}/* 校验和计算函数 */USHORT checksum(USHORT *buffer, int size) {unsigned long cksum = 0;while (size >1) {cksum += *buffer++;size -= sizeof(USHORT);}if (size) {cksum += *(UCHAR*)buffer;}cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >> 16);return (USHORT)(~cksum);}#include"stdafx.h"6.按Crtl+F5编译、运行,结果如图所示:五、测试/调试及实验结果分析。