ping程序的设计与实现.docx
- 文档编号:30204954
- 上传时间:2023-08-07
- 格式:DOCX
- 页数:28
- 大小:217.84KB
ping程序的设计与实现.docx
《ping程序的设计与实现.docx》由会员分享,可在线阅读,更多相关《ping程序的设计与实现.docx(28页珍藏版)》请在冰豆网上搜索。
ping程序的设计与实现
滁州学院
课程设计报告
课程名称:
计算机网络课程设计
设计题目:
ping程序的设计与实现
系别:
计算机与信息工程学院
专业:
计算科学与技术
组别:
第五小组
起止日期:
2011年12月1日~2011年12月8日
指导教师:
计算机科学与技术系二○一一年制
课程设计题目
Ping程序的设计与实现
组长
学号
2011220125
班级
计专
(2)班
系别
计算机与信息工程学院
专业
计算机科学与技术
组员
指导教师
课程设计目的
通过设计Ping程序,理解Ping程序的实现原理,并初步讲解了c语言网络编程技术。
本章涉及很多网络编程函数和编程技巧,包括库文件的导入;winsock的初始化、注销;socket的创建、关闭;设置socket选项;根据主机名获取IP地址;从堆中分配一定数量的空间、释放从堆中分配的空间;数据报的发送;数据报的接等。
课程设计所需环境
WindowsXP+VisualC++6.0
课程设计任务要求
实现ping的基本功能,实现ping-t
课程设计工作进度计划
序号
起止日期
工作内容
分工情况
01
2011-12-1~2011-12-2
展开思路讨论工作并搜集相关资料
02
2011-12-3~2011-12-6
具体制作,编写相关代码,制作相关窗口并实现,美化界面
。
03
2011-12-7~2011-12-8
编写并完成课程设计报告
指导教师签字:
年月日
教研室审核意见:
教研室主任签字:
年月日
课程设计任务书
一.Ping程序运行原理
在网络层,除了IP协议之外,还有一些控制协议,如ICMP,ARP,DHCP等。
1.ping的基础知识
原始套接字
原始套接字是允许访问底层传输协议的一种套接字类型。
使用原始套接字操作IP数据报,可以进行路由跟踪,Ping等。
另外,使用原始套接字需要知道许多下层协议结构的知识,所以下面讨论ICMP,IP,UDP,TCP格式。
原始套接字有两种类型,第一种类型是在IP头种使用预定义的协议,如ICMP;第二种类型是在IP头种使用自定义的协议。
下面使用创建原始套接字的方法。
创建套接字的函数是socket()或者WSASocket(),只不过要将套接字类型指定为SOCK_RAW,代码如下:
SOCKETsraw=:
:
socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
创建原始套接字时socket函数的第三个参数protocol值将成为IP头中得协议域的值。
IPPROTO_ICMP指定要使用ICMP。
原始套解释提供管理下层传输的能力。
他们可能会被恶意利用,因此,仅Administrator组的成员能够创建SOCK_RAW类型的套接字。
任何人在WindowsNT下都可以创建原始套接字,但是没有Administrator权限的人不能用它来做任何事情,因为bind函数将会失败,出错码WSAEACCES..
在上面的套接字创建代码种,我们使用ICMP,也可以使用IIGMP,UDP,IP或者原始IP,对应的宏定义分别是IPPROTO_IGMP,IPROTO_UDP,IPPROTO_IP或者IPPROTO_RAW。
其中协议标志IPPROTO_UDP,IPPROTO_IP,和IPPROTO_RAW需要启动IP_HDRINCL选项。
使用恰当的协议标志创建原始套接字之后,便可以在发送和接受调用种使用此套接字句柄了。
无论IP_HDRINCL选项是否设置,在原始套接字上接收到的数据种都会将包含IP头。
2.ICMP协议与校验和的计算
互联网上得操作由路由器紧紧地监控着。
当有异常饭送时候,具体事件通过ICMP报道,如目的不可到达,TTL超时等。
这个协议也用来测试互联网。
每个ICMP消息都封装在IP封包中,所以使用IP寻址,
ICMP消息的格式如下:
首8位表示ICMP的类型,通常可以分为请求消息和错误报告消息两类。
接下来的八位表示ICMP代码,这个域进一步定义了请求或者是消息的类型。
接下来八位表示icmp的校验和。
它提供了ICMP头和他的实际数据。
3.校验和的计算
发送ICMP报文时,必须由程序自己计算校验和,并将它填入ICMP头部的对应域中。
校验和的计算方法是:
将数据以资为单位累加到一个双字中,如果数据长度为奇数,最后一个字节将被扩展到字,累加的结果是一个双字,最后将这个双字的高16bit和低16bit相加后取反,便得到了校验和。
u_shortchecksum(u_short*buffer,intlen)
{
registerintnleft=len;
registeru_short*w=buffer;
registeru_shortanswer;
registerintsum=0;
//使用32位累加器,进行16位的反馈计算
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
//补全奇数位
if(nleft==1)
{
u_shortu=0;
*(u_char*)(&u)=*(u_char*)w;
sum+=u;
}
//将反馈的16位从高位移到低位
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return(answer);
}
3.Ping程序设计思路:
要实现ping程序,需要实现以下步骤:
(1)创建协议类型为IPPROTO_ICMP的原始套接字,设置套接字属性。
(2)创建并初始化ICMP封包。
(3)调用sendto函数向远程主机发送ICMP请求。
(4)调用recfrom函数接受ICMP响应。
初始化ICMP头时先初始化消息类型和代码域,之后是回显请求头。
程序首先定义了ICMP头的数据结构IMCP_HDR.。
ICMP_HDR的定义如下:
typedefstruct_ICMPHeader
{
u_charType;//类型
u_charCode;//代码
u_shortChecksum;//首部校验和
u_shortID;//标识
u_shortSeq;//序列号
charData;
//数据
}ICMPHDR,*PICMPHDR;
4.编程时,需要用到一些windows函数,说明如下:
(1).intWSAStartup(WORDwVersionRequested,LPWSADATAlpWSAData);
函数说明:
为了在应用程序当中调用任何一个WinsockAPI函数,首先第一件事情就是必须通过WSAStartup函数完成对Winsock服务的初始化,因此需要调用WSAStartup函数。
使用Socket的程序在使用Socket之前必须调用WSAStartup函数。
该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节指明副版本、低位字节指明主版本;
操作系统利用第二个参数返回请求的Socket的版本信息。
当一个应用程序调用WSAStartup函数时,
操作系统根据请求的Socket版本来搜索相应的Socket库,然后绑定找到的Socket库到该应用程序中。
以后应用程序就可以调用所请求的Socket库中的其它Socket函数了。
(2).SOCKETsocket(intaf,inttype,intprotocol);
函数说明:
应用程序调用socket函数来创建一个能够进行网络通信的套接字。
第一个参数指定应用程序使用的通信协议的协议族,对于TCP/IP协议族,该参数置AF_INET;
第二个参数指定要创建的套接字类型,流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、
原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它,而是由程序自行处理数据包以
及协议首部);
第三个参数指定应用程序所使用的通信协议。
(3).intsendto(SOCKETs,constcharFAR*buf,intlen,intflags,conststructsockaddrFAR*to,inttolen);
函数说明:
返回值:
实际发送数据的长度。
parameter:
s套接字
buff待发送数据的缓冲区
size缓冲区长度
Flags调用方式标志位,一般为0,改变Flags,将会改变Sendto发送的形式
addr(可选)指针,指向目的套接字的地址
lenaddr所指地址的长度
(4)intrecvfrom(SOCKETs,charFAR*buf,intlen,intflags,
structsockaddrFAR*from,intFAR*fromlen);
函数说明:
recvfrom()用来接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数len为可接收数据的最大长度.参数flags一般设0,其他数值定义参考recv().参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()函数.参数fromlen为sockaddr的结构长度.
二.程序的流程图和源码
Ping程序的设计与实现大致可分为四个模块(见图1-1),分别是:
初始化模块、功能控制模块、ping模块、mian测试模块。
图1-1
1.初始化模块:
该模块用于定义及初始化各个全局变量,为winsock加载winsock体。
(见图1-2)主要包括定义IP首部格式、定义ICMP首部格式、定义ICMP回应请求、定义ICMP回应答复。
图1-2
2.功能控制模块:
该模块是被其他模块调用,其功能包括计算校验和、发送回应请求函数、接收应答回复并进行解析、等待回应答复(主是要select模型)。
(见图1-3,1-4,1-5,1-6)
计算校验和函数源码:
图1-3
图1-4
图1-6
图1-5
3.Ping模块功能模块:
该模块是本程序的核心模块,调用其他模块实现其功能,进而实现Ping的功能。
s
4.main()函数模块:
向指定的域名或IP地址发送Echo请求报文;根据响应报文显示出Ping的结果;程序仅支持-t选项即可。
图1-8
三.运行操作及结果
在VC中运行程序后会出现如图4.1所示,提示你输入IP或网址;
2、我们先输入校园网机房主机命令,看能否ping通
3.试着使用ping–t命令,如下:
4、再输入外部网主机命令,看能否ping通,
上图为网络ping不通的情形。
源代码
源代码如下:
#include
#include
#include
#include
#pragmacomment(lib,"ws2_32.lib")//导入库文件
#defineICMP_ECHOREPLY0//ICMP回应答复
#defineICMP_ECHOREQ8//ICMP回应请求
#defineREQ_DATASIZE32//请求数据报大小
#include
usingnamespacestd;
//定义IP首部格式
typedefstruct_IPHeader
{
u_charVIHL;//版本和首部长度
u_charToS;//服务类型
u_shortTotalLen;//总长度
u_shortID;//标识号
u_shortFrag_Flags;//片偏移量
u_charTTL;//生存时间
u_charProtocol;//协议
u_shortChecksum;//首部校验和
structin_addrSrcIP;//源IP地址
structin_addrDestIP;//目的地址
}IPHDR,*PIPHDR;
//定义ICMP首部格式
typedefstruct_ICMPHeader
{
u_charType;//类型
u_charCode;//代码
u_shortChecksum;//首部校验和
u_shortID;//标识
u_shortSeq;//序列号
charData;
//数据
}ICMPHDR,*PICMPHDR;
//定义ICMP回应请求
typedefstruct_ECHOREQUEST
{
ICMPHDRicmpHdr;
DWORDdwTime;
charcData[REQ_DATASIZE];
}ECHOREQUEST,*PECHOREQUEST;
//定义ICMP回应答复
typedefstruct_ECHOREPLY
{
IPHDRipHdr;
ECHOREQUESTechoRequest;
charcFiller[256];
}ECHOREPLY,*PECHOREPLY;
/**********************************************************************************/
//计算校验和
u_shortchecksum(u_short*buffer,intlen)
{
registerintnleft=len;
registeru_short*w=buffer;
registeru_shortanswer;
registerintsum=0;
//使用32位累加器,进行16位的反馈计算
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
//补全奇数位
if(nleft==1)
{
u_shortu=0;
*(u_char*)(&u)=*(u_char*)w;
sum+=u;
}
//将反馈的16位从高位移到低位
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return(answer);
}
/**********************************************************************************************/
//发送回应请求函数
intSendEchoRequest(SOCKETs,structsockaddr_in*lpstToAddr)
{
staticECHOREQUESTechoReq;
staticnId=1;
staticnSeq=1;
intnRet;
//填充回应请求消息
echoReq.icmpHdr.Type=ICMP_ECHOREQ;
echoReq.icmpHdr.Code=0;
echoReq.icmpHdr.Checksum=0;
echoReq.icmpHdr.ID=nId++;
echoReq.icmpHdr.Seq=nSeq++;
//填充要发送的数据
for(nRet=0;nRet { echoReq.cData[nRet]='1'+nRet; } //存储发送的时间 echoReq.dwTime=GetTickCount(); //计算回应请求的校验和 echoReq.icmpHdr.Checksum=checksum((u_short*)&echoReq,sizeof(ECHOREQUEST)); //发送回应请求 nRet=sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST), 0,(structsockaddr*)lpstToAddr,sizeof(SOCKADDR_IN)); if(nRet==SOCKET_ERROR) { printf("sendto()error: %d\n",WSAGetLastError()); } return(nRet); } /*******************************************************************************/ //接收应答回复并进行解析 DWORDRecvEchoReply(SOCKETs,LPSOCKADDR_INlpsaFrom,u_char*pTTL) { ECHOREPLYechoReply; intnRet; intnAddrLen=sizeof(structsockaddr_in); //接收应答回复 nRet=recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY), 0,(LPSOCKADDR)lpsaFrom,&nAddrLen); //检验接收结果 if(nRet==SOCKET_ERROR) { printf("recvfrom()error: %d\n",WSAGetLastError()); } //记录返回的TTL *pTTL=echoReply.ipHdr.TTL; //返回应答时间 return(echoReply.echoRequest.dwTime); } /********************************************************************************/ //等待回应答复,使用select模型 intWaitForEchoReply(SOCKETs) { structtimevaltimeout; fd_setreadfds; readfds.fd_count=1; readfds.fd_array[0]=s; timeout.tv_sec=1; timeout.tv_usec=0; return(select(1,&readfds,NULL,NULL,&timeout)); } /******************************************************************************/ //PING功能实现 voidPing(char*pstrHost,boollogic) { charc; SOCKETrawSocket; LPHOSTENTlpHost; structsockaddr_indestIP; structsockaddr_insrcIP; DWORDdwTimeSent; DWORDdwElapsed; u_charcTTL; intnLoop,k=4; intnRet,minimum=100000,maximum=0,average=0; intsent=4,reveived=0,lost=0; //创建原始套接字,ICMP类型 rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);//第二个注释函数socket if(rawSocket==SOCKET_ERROR) { printf("socket()error: %d\n",WSAGetLastError()); return; } //检测目标主机 lpHost=gethostbyname(pstrHost); if(lpHost==NULL) { printf("Hostnotfound: %s\n",pstrHost); return; } //设置目标机地址 destIP.sin_addr.s_addr=*((u_longFAR*)(lpHost->h_addr));//设置目标IP destIP.sin_family=AF_INET;//地址规格 destIP.sin_port=0; //提示开始进行PING printf("\nPinging%s[%s]with%dbytesofdata: \n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE); //发起多次PING测试 for(nLoop=0;nLoop if(logic)k=k+1; //发送ICMP回应请求 SendEchoRequest(rawSocket,&destIP); //等待回复的数据 nRet=WaitForEchoReply(rawSocket); if(nRet==SOCKET_ERROR) { printf("select()error: %d\n",WSAGetLastError()); break; } if(! nRet) { lost++; printf("\nRequesttimeout."); continue; } //接收回复 dwTimeSent=RecvEchoReply(rawSocket,&srcIP,&cTTL); reveived++; //计算花费的时间 dwElapsed=GetTickCount()-dwTimeSent; if(dwElapsed>maximum)maximum=dwElapsed; if(dwElapsed average+=dwElapsed; printf("\nReplyfrom%s: bytes=%dtime=%ldmsTTL=%d", inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL); if(_kbhit())/*Use_getchtothrowkeyaway.*/ { if((c=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ping 程序 设计 实现
![提示](https://static.bdocx.com/images/bang_tan.gif)