ping程序的设计实现分析范文Word文件下载.docx

上传人:b****4 文档编号:17113971 上传时间:2022-11-28 格式:DOCX 页数:22 大小:137.77KB
下载 相关 举报
ping程序的设计实现分析范文Word文件下载.docx_第1页
第1页 / 共22页
ping程序的设计实现分析范文Word文件下载.docx_第2页
第2页 / 共22页
ping程序的设计实现分析范文Word文件下载.docx_第3页
第3页 / 共22页
ping程序的设计实现分析范文Word文件下载.docx_第4页
第4页 / 共22页
ping程序的设计实现分析范文Word文件下载.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

ping程序的设计实现分析范文Word文件下载.docx

《ping程序的设计实现分析范文Word文件下载.docx》由会员分享,可在线阅读,更多相关《ping程序的设计实现分析范文Word文件下载.docx(22页珍藏版)》请在冰豆网上搜索。

ping程序的设计实现分析范文Word文件下载.docx

实现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

SendEchoRequest()开始

定义初始化一些变量

填充要发送的数据

存储发送的时间

计算回应请求的校验和

发送回应请求

返回nRet

调用发送错误函数

结束

图1-4

RecvEchoReply()开始

接收应答回复

检验接收结果

返回应答时间

WaitForEchoReply()开始

返回timeout

图1-6

图1-5

3.Ping模块功能模块:

该模块是本程序的核心模块,调用其他模块实现其功能,进而实现Ping的功能。

s

开始

定义初始化各个局部变量

判断WSAGetLastError()是否调用成功

检测目标主机是否为NULL

设置目标主机的IP地址,开始ping

发起四次ping测试

发送ICMP回应请求

等待回复的数据

接收回复

计算花费时间

Loop是否为0

输出平均次数

输出ping结果

清除残余

4.main()函数模块:

向指定的域名或IP地址发送Echo请求报文;

根据响应报文显示出Ping的结果;

程序仅支持-t选项即可。

图1-8

三.运行操作及结果

在VC中运行程序后会出现如图4.1所示,提示你输入IP或网址;

2、我们先输入校园网机房主机命令,看能否ping通

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);

//检验接收结果

recvfrom()error:

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:

return;

//检测目标主机

lpHost=gethostbyname(pstrHost);

if(lpHost==NULL)

Hostnotfound:

%s\n"

pstrHost);

//设置目标机地址

destIP.sin_addr.s_addr=*((u_longFAR*)(lpHost->

h_addr));

//设置目标IP

destIP.sin_family=AF_INET;

//地址规格

destIP.sin_port=0;

//提示开始进行PING

\nPinging%s[%s]with%dbytesofdata:

\n"

pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);

//发起多次PING测试

for(nLoop=0;

nLoop<

k;

nLoop++){

if(logic)k=k+1;

//发送ICMP回应请求

SendEchoRequest(rawSocket,&

destIP);

//等待回复的数据

nRet=WaitForEchoReply(rawSocket);

if(nRet==SOCKET_ERROR)

{

select()error:

break;

}

if(!

nRet)

lost++;

\nRequesttimeout."

);

continue;

//接收回复

dwTimeSent=RecvEchoReply

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1