Ping程序设计(c语言课程设计)
Ping程序的设计与实现
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));}}。
计算机网络实验之Ping程序的设计与实现
课程名称计算机网络实验序号实验五实验项目 Ping程序的设计与实现2017年 03月 25 日实验报告要求1、实验报告封面填表说明(每份实验报告必须附上封面)(1)课程名称:要求与实验大纲和实验指导书中的课程名称一致。
(2)实验序号:指该课程的第几个实验。
(3)实验项目:要求与实验大纲和实验指导书中的实验项目一致。
(4)实验地点:填写完成该实验项目所在的实验室名称。
(5)实验学时:要求与实验大纲和实验指导书中完成该实验项目所需学时一致。
(6)实验类型:是指演示性、操作性、验证性、综合性、设计性。
演示性:教师操作,学生观察,验证理论、说明原理和方法。
操作性:学生按要求动手拆装、调试实验装置或上机操作,掌握其基本原理和方法。
验证性:按实验指导书(教材)要求,由学生通过操作验证所学理论,加深对理论、知识的理解,掌握基本实验知识、方法、技能、数据处理等。
综合性:实验内容涉及本课程的综合知识或相关课程的知识,运用多的知识、多种方法,按要求或自拟实验方案进行实验。
主要培养学生综合运用所学知识、实验方法和实验技能,以培养其分析、解决问题的能力。
设计性:给定实验目的、要求和实验条件,学生自己设计实验方案并加以实现的实验。
学生独立完成从查阅资料、拟定实验方案、实验方法和步骤(或系统分析和设计)、选择仪器设备(或自行设计缺制作)进行实验并完成实验全过程,形成实验报告,培养学生自主实验的能力。
2、实验报告的格式3、教师批改学生实验报告要求(1)批改:全部批改及更正错误。
(2)评分:按百分制评分,不能评分为“优、良、中、差”或“A、B、C”。
(3)签名及批改日期:任课教师必须在每份学生实验报告中签名和写上批改日期。
(4)成绩:填写学生实验成绩表,实验成绩作为考试成绩评定的依据。
(4)评语:任课教师批改学生实验报告时,应给出简明扼要的评语。
ping程序设计
//ip地址
lpdest=argv[i];
break;
}
else if(m==strlen(argv[i])-1)
datasize=atoi(argv[i]);//把字符串转换成整形
}
}
//参数是主机名
//如果获取了主机名,则输出主机名
if(host)
{
printf("(%-15s) %s\n",inet_ntoa(inaddr),host->h_name);
}
//否则输出ip地址
else
{
printf("(%-15s)\n",inet_ntoa(inaddr));
//icmp报文类型设置为回显请求
icmp_hdr->i_type=ICMP_ECHO;
icmp_hdr->i_code=0;
//获取当前进程ip作为标识符
icmp_hdr->i_id=(USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum=0;
{
inaddr.S_un.S_addr=ipopt->addr[i];
if(i!=0)
{
printf(" ");
}
//根据IP地址获取主机名
host=gethostbyaddr((char*)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr),AF_INET);
unsigned int checksum;
unsigned int sourceIP;
计算机网络课程设计(ping)
计算机网络课程设计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的简单实现课程设计
ping的简单实现课程设计一、教学目标本课程的教学目标是使学生掌握ping命令的基本使用方法,理解其工作原理,能够通过ping命令诊断网络连接问题。
具体包括:1.了解ping命令的作用和基本语法。
2.掌握如何使用ping命令检测网络连接。
3.理解ping命令的响应结果的含义。
4.能够独立操作计算机,运行ping命令。
5.能够分析ping命令的输出结果,判断网络连接状态。
6.能够根据实际情况,选择合适的ping命令参数。
情感态度价值观目标:1.培养学生对网络通信技术的兴趣和好奇心。
2.培养学生解决问题的能力和团队合作精神。
二、教学内容本课程的教学内容主要包括以下几个部分:1.ping命令的基本概念和语法。
2.ping命令的使用方法,包括如何检测网络连接。
3.ping命令的响应结果的解读。
4.如何在实际情况下,选择合适的ping命令参数。
三、教学方法本课程的教学方法包括:1.讲授法:讲解ping命令的基本概念、语法和原理。
2.实验法:引导学生实际操作ping命令,检测网络连接。
3.讨论法:分组讨论ping命令的输出结果,培养学生解决问题的能力。
四、教学资源本课程的教学资源包括:1.教材:《计算机网络基础》相关章节。
2.多媒体资料:PPT课件,网络连接检测的实验视频。
3.实验设备:计算机、网络环境。
以上是本课程的教学设计,希望能够帮助学生更好地掌握ping命令的使用,提高网络故障排除的能力。
五、教学评估本课程的教学评估将采用多元化的评估方式,以全面、客观、公正地评价学生的学习成果。
评估方式包括:1.平时表现:通过观察学生在课堂上的参与度、提问回答、小组讨论等表现,评估学生的学习态度和理解能力。
2.作业:布置相关的ping命令练习题,要求学生独立完成,通过作业的质量和完成时间评估学生的掌握程度。
3.实验报告:学生在实验过程中,需要撰写实验报告,描述实验过程、结果和收获,通过实验报告评估学生的实际操作能力和问题解决能力。
Ping命令的模拟实现课程设计
课程设计IV课程设计设计说明书Ping命令模拟实现学生姓名学号班级成绩指导教师计算机科学与技术系2011年9月9日课程设计IV课程设计评阅书题目Ping命令模拟实现学生姓名学号指导教师评语及成绩成绩:教师签名:年月日答辩教师评语及成绩成绩:教师签名:年月日教研室意见总成绩:室主任签名:年月日注:指导教师成绩60%,答辩成绩40%,总成绩合成后按五级制记入。
课程设计任务书2011—2012学年第一学期专业:学号:姓名:课程设计名称:课程设计IV课程设计设计题目:Ping命令模拟实现完成期限:自2011 年8 月29 日至2011 年9 月9 日共 2 周设计依据、要求及主要内容(可另加附页):1. 了解并掌握ICMP协议。
2. 了解Ping命令的使用,其常用格式为Ping XXX.XXX.XXX.XXX。
3. Ping命令执行原理及实现步骤。
4. 模拟ping命令的实现过程。
5. 对此次课程设计的总结指导教师(签字):教研室主任(签字):批准日期:年月日摘要随着计算机技术及网络技术的迅速发展,个人、家庭或宿舍中拥有多台计算机已变得十分的普遍,将多台计算机组建成网络可以提高资源的利用率和协同工作的效率,所以网络技术无论在教学还是在现实生活中都变得异常的重要。
在实际学习中,由于资源设备的限制,提供完善的实验环境存在一定的难度,所以提供一种模拟的组建网络的平台具有很强的现实意义。
根据Ping命令的运行的运行原理,对他进行的模拟实现,相应的其他网检查网络状态命令。
关键词:计算机;网络;Ping目录一.课题内容 (5)1.1课程设计目的 (5)1.2课程设计要求 (5)1.3 实验步骤和注意事项 (5)二. Ping命令及ICMP协议简介 (6)2.1. Ping命令简介 (6)2.2.ICMP协议简介 (6)三.实现原理和步骤 (10)3.1.实现原理 (10)3.2.实现步骤 (10)3.3.注意事项 (13)总结 (14)参考文献: (15)1.课题内容1.1课程设计目的PING程序是我们使用的比较多的用于测试网络连通性的程序。
ping程序设计与实现课程设计
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程序课程设计设计背景
ping程序课程设计设计背景一、教学目标本章节的教学目标包括以下三个方面:1.知识目标:学生能够理解ping程序的基本概念,掌握使用ping程序进行网络诊断的方法和技巧。
2.技能目标:学生能够独立操作计算机,使用ping程序对网络进行诊断,并能根据诊断结果分析网络状况。
3.情感态度价值观目标:学生通过学习ping程序的使用,增强对网络技术的兴趣和好奇心,培养解决问题的能力,提高对网络技术的应用意识和信息素养。
二、教学内容本章节的教学内容主要包括以下几个部分:1.ping程序的基本概念和作用。
2.ping程序的使用方法,包括命令的输入、参数的含义和如何解读ping结果。
3.ping程序在网络诊断中的应用,如何通过ping程序检测网络的连接性、延迟和数据包丢失情况。
4.实际操作演练,让学生通过实际操作,掌握ping程序的使用技巧。
三、教学方法为了实现本章节的教学目标,我们将采用以下几种教学方法:1.讲授法:通过讲解ping程序的基本概念、使用方法和网络诊断中的应用,让学生掌握相关知识。
2.案例分析法:通过分析实际案例,让学生了解ping程序在网络诊断中的实际应用,提高解决问题的能力。
3.实验法:让学生亲自动手操作,进行网络诊断实验,培养实际操作能力和动手能力。
四、教学资源为了支持本章节的教学内容和教学方法的实施,我们将准备以下教学资源:1.教材:《网络技术基础》2.参考书:《计算机网络与应用》3.多媒体资料:网络诊断实验演示视频4.实验设备:计算机、网络设备(如路由器、交换机等)五、教学评估本章节的教学评估主要包括以下几个方面:1.平时表现:通过观察学生在课堂上的参与程度、提问回答情况等,评估学生的学习态度和积极性。
2.作业:通过学生提交的作业,评估学生对ping程序的理解和掌握程度。
3.考试:通过期末考试,全面测试学生对ping程序的知识掌握和实际操作能力。
评估方式应客观、公正,能够全面反映学生的学习成果。
Ping 计算机网络课程设计.doc
计算机网络课程设计报告设计名称 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程序设计实验指导书
网络编程-PING程序设计实验指导书一.实验目的(1)熟悉原始套接字编程。
(2)了解网络的结构。
(3)了解网络传输底层协议。
二.实验要求PING程序是用于测试网络连通性的程序。
要求在WINDOWS环境下实现基本的PING程序功能.在命令提示符下输入:PING ***.***.***.***其中***为目的主机的IP地址,不要求支持域名,对是否带有开关变量也不做要求。
不带开关变量时,要求返回4次响应。
返回信息的格式:REPLY FROM ***.***.***.***或REQUEST TimeOut (无法PING通的情况)三.实验原理1、PING的工作原理ping 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。
ping 使用的是ICMP协议,它发送ICMP回送请求消息给目的主机。
ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。
如果源主机在一定时间内收到应答,则认为主机可达。
ICMP协议通过IP协议发送的,IP协议是一种无连接的,不可靠的数据包协议。
因此,保证数据送达的工作应该由其他的模块来完成。
其中一个重要的模块就是ICMP(网络控制报文)协议。
当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机。
给主机一个处理错误的机会,这也就是为什么说建立在IP层以上的协议是可能做到安全的原因。
ICMP数据包由8bit的错误类型和8bit的代码和16bit的校验和组成。
而前 16bit就组成了ICMP所要传递的信息。
PING利用ICMP协议包来侦测另一个主机是否可达。
原理是用类型码为0的ICMP发请求,受到请求的主机则用类型码为8的ICMP回应。
ping程序来计算间隔时间,并计算有多少个包被送达。
用户就可以判断网络大致的情况。
2、RAW模式的SOCKET编程PING程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。
dev c++实现ping程序的设计与实现
要实现一个ping程序,首先需要了解ping程序的基本工作原理。
ping程序通过向目标主机发送ICMP Echo请求并等待回应来检测网络连接。
以下是使用C语言实现一个简单的ping程序的步骤:1. 包含必要的头文件。
2. 定义一些常量和变量。
3. 编写一个函数,用于发送ICMP Echo请求。
4. 编写一个函数,用于接收ICMP Echo回应。
5. 编写主函数,解析命令行参数,调用上述函数进行ping操作。
以下是一个简单的C语言实现的ping程序示例:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <arpa/inet.h>#include <netinet/ip.h>#include <sys/socket.h>#include <netinet/icmp.h>#include <netdb.h>#define MAX_PACKET_SIZE 65507#define TIMEOUT 5void send_icmp_request(int sockfd, struct sockaddr_in *dest_addr);void receive_icmp_response(int sockfd);int main(int argc, char *argv[]) {if (argc != 2) {printf("Usage: %s <hostname>", argv[0]);return 1;}struct hostent *host = gethostbyname(argv[1]);if (host == NULL) {perror("gethostbyname");return 1;}struct sockaddr_in dest_addr;memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family = AF_INET;dest_addr.sin_port = htons(80);memcpy(&dest_addr.sin_addr, host->h_addr, host->h_length);int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);if (sockfd < 0) {perror("socket");return 1;}setsockopt(sockfd, IPPROTO_IP, IP_TTL, &TIMEOUT, sizeof(TIMEOUT));send_icmp_request(sockfd, &dest_addr);receive_icmp_response(sockfd);close(sockfd);return 0;}void send_icmp_request(int sockfd, struct sockaddr_in *dest_addr) { char packet[MAX_PACKET_SIZE];struct icmphdr *icmp_header = (struct icmphdr *)packet;memset(packet, 0, sizeof(packet));icmp_header->type = ICMP_ECHO;icmp_header->code = 0;icmp_header->checksum = 0;icmp_header->un.echo.id = htons(getpid());icmp_header->un.echo.sequence = htons(1);icmp_header->un.echo.data[0] = 'A';icmp_header->un.echo.data[1] = 'B';icmp_header->un.echo.data[2] = 'C';icmp_header->un.echo.data[3] = 'D';icmp_header->un.echo.data[4] = 'E';icmp_header->un.echo.data[5] = 'F';icmp_header->un.echo.data[6] = 'G';icmp_header->un.echo.data[7] = 'H';icmp_header->un.echo.data[8] = 'I';icmp_header->un.echo.data[9] = 'J';icmp_header->un.echo.data[10] = 'K';icmp_header->un.echo.data[11] = 'L';icmp_header->un.echo.data[12] = 'M';icmp_header->un.echo.data[13] = 'N';icmp_header->un.echo.data[14] = 'O';icmp_header->un.echo.data[15] = 'P';icmp_header->checksum = checksum(packet, sizeof(packet));sendto(sockfd, packet, sizeof(packet), 0, (struct sockaddr *)dest_addr, sizeof(*dest_addr));}void receive_icmp_response(int sockfd) {char buffer[MAX_PACKET_SIZE];struct icmphdr *icmp_header;struct sockaddr_in src_addr;socklen_t src_addr_len = sizeof(src_addr);int recv_len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&src_addr, &src_addr_len);if (recv_len < 0) {perror("recvfrom");return;}icmp_header = (struct icmphdr *)buffer;if (icmp_header->type == ICMP_ECHOREPLY) {printf("Received ICMP echo reply from %s:%d", inet_ntoa(src_addr.sin_addr), ntohs(src_addr.sin_port));printf("Round trip time: %ld ms", (long)((unsigned long)recv_len * 8 / 1000));} else {printf("Received unexpected ICMP message type: %d", icmp_header->type);}}unsigned short checksum(const void *buffer, int length) {unsigned long sum = 0;const unsigned short *shorts = (const unsigned short *)buffer;while (length > 1) {sum += *shorts++;length -= 2;}if (length == 1) {sum += htons(*(unsigned char *)buffer << 8);} else {sum += htons(*(unsigned short *)buffer);}while (sum >> 16) {sum = (sum & 0xFFFF) + (sum >> 16);}return ~sum;}```这个程序首先解析命令行参数,获取目标主机名。
Ping程序开发设计文档(范例)
课程实验开发文档题目Ping程序设计和实现所在院系计算机与通信学院专业班级学生姓名学生学号指导老师实验所在课程计算机互联网与TCP/IP200年月第一部分、Ping 的原理概述(实验目的)TCP/IP协议提供工具帮助管理员或用户识别网络问题。
其中最常用的调试工具就是使用ICMP的回送请求(Echo request)和回送应答(Echo reply)。
其原理主要是主机或路由器向指定目的站发送回送请求报文。
收到回送请求报文的目的站的机器形成一个回送应答,并把它返还给最初的发送者。
回送请求包含一个可选数据区;应答包含了在请求中所发送数据的一分副本。
回送请求及其关联的应答可用来测试目的站是否可达和是否响应。
因为请求和应答都是在IP数据报中传输的,所以应答的成功接收就证实传输系统的主要部分是正常的。
在DOS和WINDOWS操作系统中已经附带了一个实现这种功能的程序Ping,本次实验的目的就是要在熟练掌握Ping的工作原理的情况下试着自己编一个能实现类似功能的程序,以验证我们对于TCP/IP协议和ICMP协议的熟练掌握程度。
第二部分、Ping 原理的具体实现(实验过程)这个实验我是采用MFC类库来编写Ping程序的,源程序如下:/ MfcPing.cpp : Defines the class behaviors for the application.//#include "stdafx.h"#include "MfcPing.h"#include "MfcPingDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CMfcPingAppBEGIN_MESSAGE_MAP(CMfcPingApp, CWinApp)//{{AFX_MSG_MAP(CMfcPingApp)// NOTE - the ClassWizard will add and remove mapping macros here.// DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSGON_COMMAND(ID_HELP, CWinApp::OnHelp)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CMfcPingApp constructionCMfcPingApp::CMfcPingApp(){// TODO: add construction code here,// Place all significant initialization in InitInstance}/////////////////////////////////////////////////////////////////////////////// The one and only CMfcPingApp objectCMfcPingApp theApp;/////////////////////////////////////////////////////////////////////////////// CMfcPingApp initializatBOOL CMfcPingApp::InitInstance(){if (!AfxSocketInit()){AfxMessageBox(IDP_SOCKETS_INIT_FAILED);return FALSE;}AfxEnableControlContainer();// Standard initialization// If you are not using these features and wish to reduce the size// of your final executable, you should remove from the following// the specific initialization routines you do not need.#ifdef _AFXDLLEnable3dControls(); // Call this when using MFC in a shared DLL #elseEnable3dControlsStatic(); // Call this when linking to MFC statically#endifCMfcPingDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: Place code here to handle when the dialog is// dismissed with OK}else if (nResponse == IDCANCEL){// TODO: Place code here to handle when the dialog is// dismissed with Cancel}// Since the dialog has been closed, return FALSE so that we exit the// application, rather than start the application's message pump.return FALSE;}程序在编译连接后生成MFCPing. Exe,试着执行该程序,得到如下一些结果:(1)首先测试本机的TCP/IP设置是否正确,通过Ping回环地址来验证(2)在验证了本机的TCP/IP协议运行正常之后,可以通过Ping任何一个正确的IP地址来继续测试:(本实验中任选两个IP地址)由于202.103.96.68这个IP地址是长沙市163用户的DNS服务器地址,不具有完全代表性,所以我又选取了一个任意的IP加以测试:通过对于以上几个完全各异的IP地址的测试,我觉得应该说我的这个程序是正确的,它已经达到了我的预期目的。
Ping程序设计.
计算机科学与技术学院课程设计成绩单优秀:90分~100分良好:80分~89分中等:70~79分及格:60~69分不及格0分~59分武汉科技大学计算机科学与技术学院制表计算机科学与技术学院课程设计报告课程名称:计算机网络专业:软件工程班级: 09 级 01 班学号: 200922146159 姓名:丁勇指导老师:李鹏基于Socket的PING程序设计ping命令是使用频率极高的一个网络测试命令,用以测试从一个主机到另一个主机间的网络上否可达。
windows自带的ping命令具有强大的功能,它有很多选项用于实现不同的测试目的。
本章模仿windows的ping命令,用c语言实现了一个简单的命令。
本章着重讲述ping命令的实现原理和c语言的网络编程方法。
读者可以在本章的基础上,对本章实现的ping命令进行扩展,开发出功能更强大、更完善的ping命令,并进一步掌握网络编程的方法。
1、设计目的本章通过设计Ping程序,讲解Ping程序的实现原理,并初步讲解了c语言网络编程技术。
本章涉及很多网络编程函数和编程技巧。
包括库文件的导入;winsock的初始化、注销;socket的创建、关闭;设置socket选项;根据主机名获取IP地址;从堆中分配一定数量的空间、释放从堆中分配的空间;获取当前进程ID号;数据报的发送;数据报的接等。
通过本程序的训练,使读者对网络编程有一定的了解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
2、功能描述本章用c语言实现的ping命令,能用于测试一个主机到另一个主机间的联通情况,程序还提供了几个选项以实现不同的功能。
(1)实现ping功能。
程序能实现基本的ping操作,发送ICMP回显请求报文,接收应答报文。
(2)能记录路由。
程序提供了“-r”选项,用以记录从源主机到目的主机的路由。
(3)能输出指定条数的记录。
程序提供了“-n”选项,用以输出指定条数的记录。
基于C语言实现的Ping程序
【前言】Ping 是用于测试网络连接量的程序,利用它可以检查网络是否能够连通。
Ping程序的实现原理非常简单,即发送一个ICMP回声请求消息给目的地并报告是否收到所希望的ICMP回声应答。
本文采用C语言编写一个ping功能的程序。
0.ICMP协议简介ICMP是(Internet Control Message Protocol)Internet控制报文协议。
它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。
控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息。
这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。
ICMP协议是一种面向连接的协议,用于传输出错报告控制信息。
它是一个非常重要的协议,它对于网络安全具有极其重要的意义。
它是TCP/IP协议族的一个子协议,属于网络层协议,主要用于在主机与路由器之间传递控制信息,包括报告错误、交换受限控制和状态信息等。
当遇到IP数据无法访问目标、IP路由器无法按当前的传输速率转发数据包等情况时,会自动发送ICMP消息。
ICMP提供一致易懂的出错报告信息。
发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。
发送设备随后可根据 ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据报。
但是ICMP唯一的功能是报告问题而不是纠正错误,纠正错误的任务由发送方完成。
我们在网络中经常会使用到ICMP协议,比如我们经常使用的用于检查网络通不通的Ping命令(Linux和Windows中均有),这个“Ping”的过程实际上就是ICMP协议工作的过程。
还有其他的网络命令如跟踪路由的Tracert命令也是基于ICMP协议的。
ICMP报文分为两种,一是错误报告报文,二是查询报文。
每个ICMP报头均包含类型、编码和校验和这三项内容,长度为8位,8位和16位,其余选项则随ICMP 的功能不同而不同。
用C语言实现Ping程序
用C语言实现Ping程序功能大部分人用ping命令只是作为查看另一个系统的网络连接是否正常的一种简单方法。
在这篇文章中,作者将介绍如何用C语言编写一个模拟ping命令功能的程序。
ping命令是用来查在看网络上另一个主机系统的网络连接是否正常的一个工具。
ping命令的工气味儿作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到在了报文,它将把报文一模一样地传回给发送者,这有点象潜水艇声纳系统中使用的发声装置。
例如,在Linux终端上执行ping localhost命令将会看到以下结果:PING localhost.localdomain (127.0.0.1) from 127.0.0.1 : 56(84) bytes of data.64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=0 ttl=255 time=112 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=1 ttl=255 time=79 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=2 ttl=255 time=78 usec64 bytes from localhost.localdomain (127.0.0.1): icmp_seq=3 ttl=255 time=82 usec--- localhost.localdomain ping statistics ---4 packets transmitted, 4 packets received, 0% packet lossround-trip min/avg/max/mdev = 0.078/0.087/0.112/0.018 ms由上面的执行结果可以看到,ping命令执行后显示出被测试系统主机名和相应IP地址、返回给当前主机的ICMP报文顺序号、ttl生存时间和往返时间rtt(单位是毫秒,即千分之一秒)。
ping程序的设计实现分析范文教案资料
p i n g程序的设计实现分析范文滁州学院课程设计报告课程名称:计算机网络课程设计设计题目: ping程序的设计与实现系别:计算机与信息工程学院专业:计算科学与技术组别:第五小组起止日期: 2011年12月1日~2011年12月8日指导教师:计算机科学与技术系二○一一年制课程设计任务书一.Ping 程序运行原理在网络层,除了IP协议之外,还有一些控制协议,如ICMP, ARP, DHCP 等。
1.ping的基础知识原始套接字原始套接字是允许访问底层传输协议的一种套接字类型。
使用原始套接字操作IP数据报,可以进行路由跟踪, Ping等。
另外,使用原始套接字需要知道许多下层协议结构的知识,所以下面讨论ICMP,IP, UDP, TCP格式。
原始套接字有两种类型,第一种类型是在IP头种使用预定义的协议,如ICMP;第二种类型是在IP头种使用自定义的协议。
下面使用创建原始套接字的方法。
创建套接字的函数是socket()或者WSASocket(),只不过要将套接字类型指定为SOCK_RAW,代码如下:SOCKET sraw = ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);创建原始套接字时socket函数的第三个参数protocol值将成为IP头中得协议域的值。
IPPROTO_ICMP指定要使用ICMP。
原始套解释提供管理下层传输的能力。
他们可能会被恶意利用,因此,仅Administrator组的成员能够创建SOCK_RAW类型的套接字。
任何人在Windows NT下都可以创建原始套接字,但是没有Administrator权限的人不能用它来做任何事情,因为bind函数将会失败,出错码WSAEACCES..在上面的套接字创建代码种,我们使用ICMP,也可以使用IIGMP, UDP, IP 或者原始IP,对应的宏定义分别是IPPROTO_IGMP, IPROTO_UDP, IPPROTO_IP 或者IPPROTO_RAW。
Ping程序设计代码及报告
实验报告
课程计算机网络课程设计实验名称Ping程序的设计与实现专业班级08级信管(2)班
姓名
学号**********
实验日期2011年11月8日
System.gc();
end=System.currentTimeMillis();
}
public long duration()//计算响应时间的方法
{
return(end-start);
}
public void reset()//重置开始和结束时间
{
start=0; end=0;
}
}
四. 视图如下:
五.实验总结
通过这次实验, 我掌握了Java网络编程中对应的相关基础知识, 知道了ICMP协议以及跟踪运行Java网络包了解网络编程实现的细节问题, 并了解了Ping命令的功能。
我认识了ping 作为一种通信命令, 是IP协议的一部分, 利用他可以检查网络是否能够连通, 它也可以帮助我们分析网络故障。
通过这次实验,我掌握了Java网络编程中对应的相关基础知识,知道了ICMP 协议以及跟踪运行Java网络包了解网络编程实现的细节问题,并了解了Ping命令的功能。
我认识了ping作为一种通信命令,是IP协议的一部分,利用他可以检查网络是否能够连通,它也可以帮助我们分析网络故障。
计算机网络程序设计(c语言课程设计)
ping程序设计ping命令是使用频率极高的一个网络测试命令,用以测试从一个主机到另一个主机间的网络上否可达。
windows自带的ping命令具有强大的功能,它有很多选项用于实现不同的测试目的。
本章模仿windows的ping命令,用c语言实现了一个简单的命令。
本章着重讲述ping命令的实现原理和c语言的网络编程方法。
读者可以在本章的基础上,对本章实现的ping命令进行扩展,开发出功能更强大、更完善的ping命令,并进一步掌握网络编程的方法。
9.1 设计目的本章通过设计Ping程序,讲解Ping程序的实现原理,并初步讲解了c语言网络编程技术。
本章涉及很多网络编程函数和编程技巧。
包括库文件的导入;winsock的初始化、注销;socket 的创建、关闭;设置socket选项;根据主机名获取IP地址;从堆中分配一定数量的空间、释放从堆中分配的空间;获取当前进程ID号;数据报的发送;数据报的接等。
通过本程序的训练,使读者对网络编程有一定的了解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
9.2功能描述本章用 c 语言实现的ping命令,能用于测试一个主机到另一个主机间的联通情况,程序还提供了几个选项以实现不同的功能。
(1)实现ping功能。
程序能实现基本的ping操作,发送ICMP回显请求报文,接收显应答报文。
(2)能记录路由。
程序提供了“-r”选项,用以记录从源主机到目的主机的路由。
(3)能输出指定条数的记录。
程序提供了“-n”选项,用以输出指定条数的记录。
(4)能按照指定大小输出每条记录。
程序提供了“datasize”选项,用以指定输出的数据报的大小。
(5)能输出用户帮助。
程序提供了用户帮助,显示程序提供的选项以及选项格式等。
9.3 总体设计9.3.1 功能模块设计1. 功能模块图本系统共有 4 个模块,分别是初始化模块、功能控制模块、数据控制模块、数据报解读模块和ping测试模块,如图9.1所示。
ping的实现课程设计
ping的实现 课程设计一、课程目标知识目标:1. 理解ping命令的基本工作原理,掌握其网络诊断功能;2. 学习并掌握使用ping命令检测网络连通性的方法;3. 了解ping命令的参数设置及其作用。
技能目标:1. 学会运用ping命令进行简单的网络故障排查;2. 能够通过ping命令的结果,分析网络延迟、丢包等问题;3. 培养学生对网络故障的敏感度,提高解决问题的能力。
情感态度价值观目标:1. 培养学生对计算机网络知识的兴趣,激发探索精神;2. 培养学生团队合作意识,学会在网络环境中与他人共同解决问题;3. 强化网络安全意识,让学生明白网络诊断工具的正确使用方法。
课程性质:本课程为计算机网络基础课程,旨在帮助学生掌握网络诊断的基本方法,提高实际操作能力。
学生特点:学生为初中年级,对计算机网络知识有一定的了解,具备基本的计算机操作能力。
教学要求:通过本章节的学习,要求学生能够熟练运用ping命令进行网络诊断,并具备一定的网络故障排查能力。
将目标分解为具体的学习成果,以便后续的教学设计和评估。
二、教学内容1. 理论知识:- 计算机网络基础知识回顾,重点强调TCP/IP协议;- ping命令的工作原理,介绍ICMP协议的作用;- ping命令的参数及其功能解释,如:-t、-a、-n、-l等。
2. 实践操作:- 演示如何使用ping命令检测网络连通性;- 指导学生使用ping命令检测本地网络中的设备;- 实践案例:分析ping命令返回结果,判断网络延迟、丢包等问题。
3. 教学大纲:- 第一课时:计算机网络知识回顾,介绍ping命令及其工作原理;- 第二课时:ping命令的参数介绍,演示如何使用ping命令;- 第三课时:实践操作,学生分组进行网络诊断,分析ping命令结果;- 第四课时:总结与拓展,讨论网络故障排查的其他方法,强化网络安全意识。
教材关联:教学内容与课本第三章“网络诊断与故障排除”相关,结合课本案例,使学生更好地掌握网络诊断技巧。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
07网络工程本制作人:北-624寝室负责人:赖文斌第四篇网络编程第九章ping程序设计ping命令是使用频率极高的一个网络测试命令,用以测试从一个主机到另一个主机间的网络上否可达。
windows自带的ping命令具有强大的功能,它有很多选项用于实现不同的测试目的。
本章模仿windows的ping命令,用c语言实现了一个简单的命令。
本章着重讲述ping命令的实现原理和c语言的网络编程方法。
读者可以在本章的基础上,对本章实现的ping命令进行扩展,开发出功能更强大、更完善的ping命令,并进一步掌握网络编程的方法。
9.1 设计目的本章通过设计Ping程序,讲解Ping程序的实现原理,并初步讲解了c语言网络编程技术。
本章涉及很多网络编程函数和编程技巧。
包括库文件的导入;winsock的初始化、注销;socket 的创建、关闭;设置socket选项;根据主机名获取IP地址;从堆中分配一定数量的空间、释放从堆中分配的空间;获取当前进程ID号;数据报的发送;数据报的接等。
通过本程序的训练,使读者对网络编程有一定的了解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
9.2功能描述本章用 c 语言实现的ping命令,能用于测试一个主机到另一个主机间的联通情况,程序还提供了几个选项以实现不同的功能。
(1)实现ping功能。
程序能实现基本的ping操作,发送ICMP回显请求报文,接收显应答报文。
(2)能记录路由。
程序提供了“-r”选项,用以记录从源主机到目的主机的路由。
(3)能输出指定条数的记录。
程序提供了“-n”选项,用以输出指定条数的记录。
(4)能按照指定大小输出每条记录。
程序提供了“datasize”选项,用以指定输出的数据报的大小。
(5)能输出用户帮助。
程序提供了用户帮助,显示程序提供的选项以及选项格式等。
9.3 总体设计9.3.1 功能模块设计1. 功能模块图本系统共有 4 个模块,分别是初始化模块、功能控制模块、数据控制模块、数据报解读模块和ping测试模块,如图9.1所示。
各模块功能描述如下。
图9.1 系统模块图(1) 初始化模块。
改模块用于初始化各个全局变量,为全局变量赋初始值;初始化,加载库。
(2)功能控制模块。
改模块是被其它模块调用,其功能包括获取参数、计算校验和填充数据报文、释放占用资源和显示用户帮助。
(3)数据报解读模块。
改模块用于解读接收到的报文和选项。
(4)测试模块。
改模块是本程序的核心模块,调用其他模块实现其功能,主要是实现的功能。
2.系统流程图系统执行的流程图9.2所示。
程序首先调用IniPing()函数初始化各全局变量,然后GetArgments()函数获取用户输入的参数,检查用户输入的参数,如果参数不正确或者没有输入参数,则显示用户帮助信息(User help ),并结束程序;如果参数正确,则对指定目的地执行Ping命令,如果Ping通,则显示Ping结果并释放占用资源,如果没有Ping通,则报告错误信息,并释放占用资源。
图9.2 系统流程图3.参数获取(GetArgments()函数)流程图获取的参数包括“-r”(记录路由)、“-n”(记录条数程序,任意的整数)和datasize(数据报大小)。
程序首先判断每一个参数的第一字符,如果第一个字符是“-”(短横线),则认为是“-r”或者“-n”中的一个,然后作进一步判断。
如果该参数的第二个字符是数字,则判断该参数为记录的条数,如果该参数的第二个字符是“r”,则判断该参数为“-r”,用于记录路由;如果参数的第一个字符是数字,则认为参数是IP地址;或者datasize,然后作进一步的判断。
如果该参数中不存在非数字的字符,则判断该参数为datasize;如果存在非数字的字符,则判断该参数为IP地址;其他情况则判断为主机名。
参数获取的流程如图9.3所示。
图9.3 参数获取流程图4.ping()函数流程图ping()函数是本程序的核心部分它调用其他模块的函数来实现,其主要步骤包括创建接字,设置路由选项(如果需要的话)、设置接收和发送超时值、名字解析(如果需要的话)、分配内存、创建ICMP报文、发送ICMP请求报文、接收ICMP应答报文和解读ICMP报文。
其执行流程如图9.4所示。
图9.4 Ping 函数流程图9.3.2数据结构设计本程序定义了3个结构体:-iphdr、-icmphdr、和-ipotionhdr,分别用于存放IP报头信息、ICM P报头信息和IP路由选项信息。
1.定义IP报头结构体Typedef struct _iphdr{Unsigned int h_len:4;Unsigned int version:4;Unsigned char tos;Unsigned short total_len;Unsigned short ident;Unsigned short frag_flags;Unsigned char ttl;Unsigned chor proto;Unsigned short checksum;Unsigned int sourceIP;Unsigned int destIP;} IpHeader;h-len:4 : 表示IP报头长度,首部长度指的是首部占32bit字的数目,包括任何选项。
由于它是一个4bit 字段,因此首部最长为60个字节,不包括任何选项的IP报头是20个字节。
Version:4: 表示IP的版本号,这里表示Ipv4.。
Top: 表示服务的类型,可以表示最小时延,最大吞吐量,最高可靠性和最小费用。
Total –len: 整个IP数据报的总长度。
Ident: 唯一的标识符,标识主机发送的每一份数据报。
Frag-flags: 分段标志,表示过长的数据报是否要分段。
Ttl: 生存期,表示数据报可以经过的最多路由器数。
Proto: 协议类型(TCP、UDP等)。
Checksum: 校验和。
sourceIP: 源IP地址。
destIP: 目的IP地址。
2.定义ICMP报头结构体Typedef struct –icmphdr{BYTE i_type;BYTE i_code :USHORT i_cksum;USHORT i_id;USHORT i_seq;ULONG timestamp;} IcmpHeader;其中各字段表示意义如下。
I_tye : ICMP报文类型。
I_code : 该类型中的代码号,一种ICMP 报文的类型号和该类型中的代码号共同决定。
、I_cksum: 校验和。
I_seq: 序列号,序列号从0开始,每发送一次新的回显请求就加1. Timestamp: 时间。
3.定义IP 选项结构体Typedef struct _ipoptionhdr{Unsigned char code;Unsigned char len;Unsigned char ptr;Unsigned loang addr[9];} IcmpHeader;Code: 指明IP 选项类型,对于路由记录选项,它的值是7。
Len: 选项头长度。
Ptr: 地址指针字段,是一个基于1的指针,指向存放下一个IP地址的位置。
addr[9]: 记录的Ip地址列表,由于IP首部中选项的空间有限,所以可以记录的Ip地址最多是9个。
9.33函数功能描述1)IntPing()函数原型:void IntPing()IntPing()函数用于初始化ping 所需的全局变量,为各个变量赋初始值。
2)userHelp()函数原型:void userHelp()userHelp()函数用于显示用户帮助信息。
当程序检查到参数错误或者没有必要的参数(如主机IP地址或者主机名)时,则会调用此函数显示帮助信息。
3) GetArgments()函数原型:void GetArgments(int argc, char**argv)GetArgments()函数用于获取用户提交的参数。
其中argc 表示获取的参数个数,argv 用于存储获取的参数,这两个形参和主函数中的形参表示的意义一样的。
4)checkSum()函数原型:USHORT checkSum(USHORT *buffer,int size)checkSum()函数用于计算校验和。
计算过程是首先把数据报头中的校验和字段设置为0,然后对首部中每个16bit 进行二字段进制反码求和(整个首部看成是由一串16bit 的字组成),结果存在校验和字段中。
其中buffer 用于存放ICMP数据,size表示ICMP报文大小。
5)FillCMPData()函数原型:void FillCMPData()FillCMPData()函数用于填充ICMP数据报中各个字段。
其中icmp_data 表示ICMP数据,datasize 表示ICMP报文大小。
6) reeRes()函数原型:void reeRes()reeRes()函数用于释放占用的资源,包括关闭初始化socket 调用的函数的、关闭创建的socket和释放分配的内存等。
7)DecodeIPOptions()函数原型:void DecodeIPOptions()DecodeIPOptions()函数用于解读IP选项,从中读出从源主机到目的主机经过的路由,并输出路由信息。
Buf表示存放接收到的ICMP报文的缓冲区,bytes表示接收到的字节数。
8)DecodelICMPHeader()函数原型:void DecodelICMPHeader(char*buf,int bytes,SOCKADDR_IN*from) DecodelICMPHeader()函数用于解读ICMP报文信息。
Buf表示存放接收到的ICMP报文的缓冲区,bytes表示接收到的字节数,from 表示发送ICMP回显应答的主机IP地址。
9)PingTest()函数原型:void PingTest(int timeout)PingTest()函数用于进行Ping操作。
其中timeout表示设定的发送超时值。
9.4程序实现9.1.4 源码分析1. 程序预处理/*导入库文件*/#pragma comment( lib, "ws2_32.lib" )/*加载头文件*/#include <winsock2.h>#include <ws2tcpip.h>#include <stdio.h>#include <stdlib.h>#include <math.h>/*定义常量*//*表示要记录路由*/#define IP_RECORD_ROUTE 0x7/*默认数据报大小*/#define DEF_PACKET_SIZE 32/*最大的ICMP数据报大小*/#define MAX_PACKET 1024/*最大IP头长度*/#define MAX_IP_HDR_SIZE 60/*ICMP报文类型,回显请求*/#define ICMP_ECHO 8/*ICMP报文类型,回显应答*/#define ICMP_ECHOREPLY 0/*最小的ICMP数据报大小*/#define ICMP_MIN 8/*自定义函数原型*/void InitPing();void UserHelp();void GetArgments(int argc, char** argv);USHORT CheckSum(USHORT *buffer, int size);void FillICMPData(char *icmp_data, int datasize);void FreeRes();void DecodeIPOptions(char *buf, int bytes);void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN* from); void PingTest(int timeout);/*IP报头字段数据结构*/typedef struct _iphdr{unsigned int h_len:4; /*IP报头长度*/unsigned int version:4; /*IP的版本号*/unsigned char tos; /*服务的类型*/unsigned short total_len; /*数据报总长度*/unsigned short ident; /*惟一的标识符*/unsigned short frag_flags; /*分段标志*/unsigned char ttl; /*生存期*/unsigned char proto; /*协议类型(TCP、UDP等)*/unsigned short checksum; /*校验和*/unsigned int sourceIP; /*源IP地址*/unsigned int destIP; /*目的IP地址*/} IpHeader;/*ICMP报头字段数据结构*/typedef struct _icmphdr{BYTE i_type; /*ICMP报文类型*/BYTE i_code; /*该类型中的代码号*/USHORT i_cksum; /*校验和*/USHORT i_id; /*惟一的标识符*/USHORT i_seq; /*序列号*/ULONG timestamp; /*时间戳*/} IcmpHeader;/*IP选项头字段数据结构*/typedef struct _ipoptionhdr{unsigned char code; /*选项类型*/unsigned char len; /*选项头长度*/unsigned char ptr; /*地址偏移长度*/unsigned long addr[9]; /*记录的IP地址列表*/ } IpOptionHeader;/*定义全局变量*/SOCKET m_socket;IpOptionHeader IpOption;SOCKADDR_IN DestAddr;SOCKADDR_IN SourceAddr;char *icmp_data;char *recvbuf;USHORT seq_no ;char *lpdest;int datasize;BOOL RecordFlag;double PacketNum;BOOL SucessFlag;2.初始化模块/*初始化变量函数*/void InitPing(){WSADATA wsaData;icmp_data = NULL;seq_no = 0;recvbuf = NULL;RecordFlag = FALSE;lpdest = NULL;datasize = DEF_PACKET_SIZE;PacketNum = 5;SucessFlag = FALSE;/*Winsock初始化*/if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){/*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/printf("WSAStartup() failed: %d\n", GetLastError());return ;}m_socket = INV ALID_SOCKET;}3.功能控制模块/*显示信息函数*/void UserHelp(){printf("UserHelp: ping -r <host> [data size]\n");printf(" -r record route\n");printf(" -n record amount\n");printf(" host remote machine to ping\n");printf(" datasize can be up to 1KB\n");ExitProcess(-1);}/*获取ping选项函数*/void GetArgments(int argc,char** argv){int i;int j;int exp;int len;int m;/*如果没有指定目的地地址和任何选项*/if(argc == 1){printf("\nPlease specify the destination IP address and the ping option as follow!\n");UserHelp();}for(i = 1; i < argc; i++){if (argv[i][0] == '-'){/*选项指示要获取记录的条数*/if(isdigit(argv[i][1])){PacketNum = 0;for(j=len-1,exp=0;j>=1;j--,exp++)/*根据argv[i][j]中的ASCII值计算要获取的记录条数(十进制数)*/PacketNum += ((double)(argv[i][j]-48))*pow(10,exp);}else{switch (tolower(argv[i][1])){/*选项指示要获取路由信息*/case 'r':RecordFlag = TRUE;break;/*没有按要求提供选项*/default:UserHelp();break;}}}/*参数是数据报大小或者IP地址*/else if (isdigit(argv[i][0])){for(m=1;m<len;m++){if(!(isdigit(argv[i][m]))){/*是IP地址*/lpdest = argv[i];break;}/*是数据报大小*/else if(m==len-1)datasize = atoi(argv[i]);}}/*参数是主机名*/else}}/*求校验和函数*/USHORT CheckSum(USHORT *buffer, int size){unsigned long cksum=0;while (size > 1){cksum += *buffer++;size -= sizeof(USHORT);}if (size){cksum += *(UCHAR*)buffer;}/*对每个16bit进行二进制反码求和*/cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >>16);return (USHORT)(~cksum);}/*填充ICMP数据报字段函数*/void FillICMPData(char *icmp_data, int datasize){IcmpHeader *icmp_hdr = NULL;char *datapart = NULL;icmp_hdr = (IcmpHeader*)icmp_data;/*ICMP报文类型设置为回显请求*/icmp_hdr->i_type = ICMP_ECHO;icmp_hdr->i_code = 0;/*获取当前进程IP作为标识符*/icmp_hdr->i_id = (USHORT)GetCurrentProcessId();icmp_hdr->i_cksum = 0;icmp_hdr->i_seq = 0;datapart = icmp_data + sizeof(IcmpHeader);/*以数字0填充剩余空间*/memset(datapart,'0',datasize-sizeof(IcmpHeader)); }/*释放资源函数*/void FreeRes(){/*关闭创建的套接字*/if (m_socket != INV ALID_SOCKET)closesocket(m_socket);/*释放分配的内存*/HeapFree(GetProcessHeap(), 0, recvbuf);HeapFree(GetProcessHeap(), 0, icmp_data);/*注销WSAStartup()调用*/WSACleanup();return ;}4.数据报解读模块/*解读IP选项头函数*/void DecodeIPOptions(char *buf, int bytes){IpOptionHeader *ipopt = NULL;IN_ADDR inaddr;int i;HOSTENT *host = NULL;/*获取路由信息的地址入口*/ipopt = (IpOptionHeader *)(buf + 20);printf("RR: ");for(i = 0; i < (ipopt->ptr / 4) - 1; i++){inaddr.S_un.S_addr = ipopt->addr[i];if (i != 0)printf(" ");/*根据IP地址获取主机名*/host = gethostbyaddr((char *)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr), AF_INET);/*如果获取到了主机名,则输出主机名*/if (host)printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);/*否则输出IP地址*/elseprintf("(%-15s)\n", inet_ntoa(inaddr));}return;}/*解读ICMP报头函数*/void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN *from){IpHeader *iphdr = NULL;IcmpHeader *icmphdr = NULL;unsigned short iphdrlen;DWORD tick;static int icmpcount = 0;iphdr = (IpHeader *)buf;/*计算IP报头的长度*/iphdrlen = iphdr->h_len * 4;tick = GetTickCount();/*如果IP报头的长度为最大长度(基本长度是20字节),则认为有IP选项,需要解读IP选项*/if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount))/*解读IP选项,即路由信息*/DecodeIPOptions(buf, bytes);/*如果读取的数据太小*/if (bytes < iphdrlen + ICMP_MIN){printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));}icmphdr = (IcmpHeader*)(buf + iphdrlen);/*如果收到的不是回显应答报文则报错*/if (icmphdr->i_type != ICMP_ECHOREPLY){printf("nonecho type %d recvd\n", icmphdr->i_type);return;}/*核实收到的ID号和发送的是否一致*/if (icmphdr->i_id != (USHORT)GetCurrentProcessId()){printf("someone else's packet!\n");return ;}SucessFlag = TRUE;/*输出记录信息*/printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));printf(" icmp_seq = %d. ", icmphdr->i_seq);printf(" time: %d ms", tick - icmphdr->timestamp);printf("\n");icmpcount++;return;}5.Ping 测试模块/*ping函数*/void PingTest(int timeout){int ret;int readNum;int fromlen;struct hostent *hp = NULL;/*创建原始套接字,该套接字用于ICMP协议*/m_socket = WSASocket(AF_INET, SOCK_RA W, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED);/*如果套接字创建不成功*/if (m_socket == INV ALID_SOCKET){printf("WSASocket() failed: %d\n", WSAGetLastError());return ;}/*若要求记录路由选项*/if (RecordFlag){/*IP选项每个字段用0初始化*/ZeroMemory(&IpOption, sizeof(IpOption));/*为每个ICMP包设置路由选项*/IpOption.code = IP_RECORD_ROUTE;IpOption.ptr = 4;IpOption.len = 39;ret = setsockopt(m_socket, IPPROTO_IP, IP_OPTIONS,(char *)&IpOption, sizeof(IpOption));if (ret == SOCKET_ERROR){printf("setsockopt(IP_OPTIONS) failed: %d\n",WSAGetLastError());}}/*设置接收的超时值*/readNum = setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout, sizeof(timeout));if(readNum == SOCKET_ERROR){printf("setsockopt(SO_RCVTIMEO) failed: %d\n",WSAGetLastError());return ;}/*设置发送的超时值*/timeout = 1000;readNum = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));if (readNum == SOCKET_ERROR){printf("setsockopt(SO_SNDTIMEO) failed: %d\n",WSAGetLastError());return ;}/*用0初始化目的地地址*/memset(&DestAddr, 0, sizeof(DestAddr));/*设置地址族,这里表示使用IP地址族*/DestAddr.sin_family = AF_INET;if ((DestAddr.sin_addr.s_addr = inet_addr(lpdest)) == INADDR_NONE){/*名字解析,根据主机名获取IP地址*/if ((hp = gethostbyname(lpdest)) != NULL){/*将获取到的IP值赋给目的地地址中的相应字段*/memcpy(&(DestAddr.sin_addr), hp->h_addr, hp->h_length);/*将获取到的地址族值赋给目的地地址中的相应字段*/DestAddr.sin_family = hp->h_addrtype;printf("DestAddr.sin_addr = %s\n", inet_ntoa(DestAddr.sin_addr));}/*获取不成功*/else{printf("gethostbyname() failed: %d\n",WSAGetLastError());return ;}}/*数据报文大小需要包含ICMP报头*/datasize += sizeof(IcmpHeader);/*根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存的内容将被初始化为0*/icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET);recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET);/*如果分配内存不成功*/if (!icmp_data){printf("HeapAlloc() failed: %d\n", GetLastError());return ;}/* 创建ICMP报文*/memset(icmp_data,0,MAX_PACKET);FillICMPData(icmp_data,datasize);while(1){static int nCount = 0;int writeNum;/*超过指定的记录条数则退出*/if (nCount++ == PacketNum)break;/*计算校验和前要把校验和字段设置为0*/((IcmpHeader*)icmp_data)->i_cksum = 0;/*获取操作系统启动到现在所经过的毫秒数,设置时间戳*/((IcmpHeader*)icmp_data)->timestamp = GetTickCount();/*设置序列号*/((IcmpHeader*)icmp_data)->i_seq = seq_no++;/*计算校验和*/((IcmpHeader*)icmp_data)->i_cksum = CheckSum((USHORT*)icmp_data,datasize);/*开始发送ICMP请求*/writeNum = sendto(m_socket, icmp_data, datasize, 0,(struct sockaddr*)&DestAddr, sizeof(DestAddr));/*如果发送不成功*/if (writeNum == SOCKET_ERROR){/*如果是由于超时不成功*/if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}/*其他发送不成功原因*/printf("sendto() failed: %d\n", WSAGetLastError());return ;}/*开始接收ICMP应答*/fromlen = sizeof(SourceAddr);readNum = recvfrom(m_socket, recvbuf, MAX_PACKET, 0,(struct sockaddr*)&SourceAddr, &fromlen);/*如果接收不成功*/if (readNum == SOCKET_ERROR){/*如果是由于超时不成功*/if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}/*其他接收不成功原因*/printf("recvfrom() failed: %d\n", WSAGetLastError());return ;}/*解读接收到的ICMP数据报*/DecodeICMPHeader(recvbuf, readNum, &SourceAddr);}}6.主函数int main(int argc, char* argv[]){InitPing();GetArgments(argc, argv);PingTest(1000);/*延迟1秒*/Sleep(1000);if(SucessFlag)printf("\nPing end, you have got %.0f records!\n",PacketNum);elseprintf("Ping end, no record!");FreeRes();getchar();return 0;}。