ping程序的设计实现分析范文Word格式.docx
《ping程序的设计实现分析范文Word格式.docx》由会员分享,可在线阅读,更多相关《ping程序的设计实现分析范文Word格式.docx(27页珍藏版)》请在冰豆网上搜索。
根据主机名获取socketsocket的创建、关闭;
设置从堆中分配一定数量的空间、释放从堆中分配的地址;
IP空间;
数据报的发送;
数据报的接等。
mai功Ping初测能模始n块试控化模制模Nleft>
1
(是)位的反馈计算进行1632使用位累加器,
sum+=*w++;
nleft-=2;
存储发送的时间计算回应请求的校验和结束接收检验结果是检测目标主机
课程设计所需环境WindowsXP+VisualC++6.0NULL
是否为
课程设计任务要求ping-t的基本功能,实现实现pingNleft=1应送回发请求否
课程设计工作进度计划是)补全奇数位(是地址,IP设置目标主机的
序号
起止日期sum+=u;
工作内容ping
开始
分工情况
01否
2011-12-1~2011-12-2将反馈的(
sum=(sum>
>
16)+
展开思路讨论工作并搜集相关资料)
位从高位移到低位16nRet
返回
02
2011-12-3~2011-12-6(sum&
0xffff);
(sum+=sum
16);
调用发送错误函数
具体制作,编写相关代码,制作相关窗口并实现,美化界面>
次四发起测试ping
。
ICMP回应请求发送
03
2011-12-7~2011-12-8
answer
编写并完成课程设计报告结束清除残余
等待回复的数据
月日年指导教师签字:
结束接收回复
教研室审核意见:
教研室主任签字:
年月日结束计算花费时间否
是否Loop0为是ping输出结果输出平均次数
一.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)
}
//补全奇数位
if(nleft==1)
u_shortu=0;
*(u_char*)(&
u)=*(u_char*)w;
sum+=u;
//将反馈的16位从高位移到低位
16)+(sum&
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为了在应用程序当中调用任何一个Socket使用因此需要调用服务的初始化,WSAStartup函数。
WSAStartup函数完成对Winsock函数。
Socket之前必须调用WSAStartup的程序在使用版本,其中高位字节指明副版本、低位字Socket该函数的第一个参数指明程序请求使用的节指明主版本;
WSAStartup的版本信息。
当一个应用程序调用操作系统利用第二个参数返回请求的Socket函数时,库到该应Socket版本来搜索相应的Socket库,然后绑定找到的操作系统根据请求的Socket用程序中。
函数了。
库中的其它SocketSocket以后应用程序就可以调用所请求的
(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.体。
winsockwinsock加载该模块用于定义及初始化各个全局变量,为回应请求、定义ICMPICMP首部格式、定义(见图1-2)主要包括定义IP首部格式、定义回应答复。
ICMP
初始化模块定定定定义义义义ICMIPICMICM回P首P回首P应部部应答格格请式求式复
1-2
图功能控制模块:
2.该模块是被其他模块调用,其功能包括计算校验和、发送回应请求)1-5,1-61-41-3(模型)(主是要接收应答回复并进行解析、函数、等待回应答复select。
见图,,计算校验和函数源码:
1-3
图.
1-4
RecvEchoReplWaitForEchoR1-6
图是
返回应答时间
调用发送错误
函数
结束
1-5
图模块功能模块:
3.Ping调用其他模块实现其功该模块是本程序的核心模块,的功能。
能,进而实现Ping
开始.
s
精品文档函数模块:
4.main()请求报文;
根据响应报地址发送Echo向指定的域名或IP选项即可。
Ping的结果;
程序仅支持-t文显示出
开始WSAStartup是否成功()
加载失败否截取后三位字符-t
为了实现ping()
调用释放资源结束
1-8
图三.运行操作及结果;
或网址4.1中运行程序后会出现如图所示,提示你输入IPVC在
ping2、我们先输入校园网机房主机命令,看能否通.
3.试着使用ping–t命令,如下:
4、再输入外部网主机命令,看能否ping通,
上图为网络ping不通的情形。
源代码
源代码如下:
#include<
stdio.h>
stdlib.h>
winsock.h>
#include<
conio.h>
#pragmacomment(lib,ws2_32.lib)//导入库文件
#defineICMP_ECHOREPLY0//ICMP回应答复
#defineICMP_ECHOREQ8//ICMP回应请求
#defineREQ_DATASIZE32//请求数据报大小
iostream>
/*******************/
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首部格式
u_charType;
u_charCode;
u_shortSeq;
charData;
//定义ICMP回应请求
typedefstruct_ECHOREQUEST
ICMPHDRicmpHdr;
DWORDdwTime;
charcData[REQ_DATASIZE];
}ECHOREQUEST,*PECHOREQUEST;
//定义ICMP回应答复
typedefstruct_ECHOREPLY
IPHDRipHdr;
ECHOREQUESTechoRequest;
charcFiller[256];
}ECHOREPLY,*PECHOREPLY;
/**********************************************************************************/
//计算校验和
registerintnleft=len;
registeru_short*w=buffer;
registeru_shortanswer;
registerintsum=0;
//使用32位累加器,进行16位的反馈计算
while(nleft>
{
sum+=*w++;
nleft-=2;
}
//补全奇数位
if(nleft==1)
u_shortu=0;
*(u_char*)(&
sum+=u;
//将反馈的16位从高位移到低位
sum=(sum>
sum+=(sum>
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<
REQ_DATASIZE;
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;
intnAddrLen=sizeof(structsockaddr_in);
//接收应答回复
nRet=recvfrom(s,(LPSTR)&
echoReply,sizeof(ECHOREPLY),
0,(LPSOCKADDR)lpsaFrom,&
nAddrLen);
//检验接收结果
printf(
ecvfrom()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类型
rawSo