计算机网络课程设计ping工具.docx

上传人:b****2 文档编号:2435949 上传时间:2023-05-03 格式:DOCX 页数:21 大小:264.99KB
下载 相关 举报
计算机网络课程设计ping工具.docx_第1页
第1页 / 共21页
计算机网络课程设计ping工具.docx_第2页
第2页 / 共21页
计算机网络课程设计ping工具.docx_第3页
第3页 / 共21页
计算机网络课程设计ping工具.docx_第4页
第4页 / 共21页
计算机网络课程设计ping工具.docx_第5页
第5页 / 共21页
计算机网络课程设计ping工具.docx_第6页
第6页 / 共21页
计算机网络课程设计ping工具.docx_第7页
第7页 / 共21页
计算机网络课程设计ping工具.docx_第8页
第8页 / 共21页
计算机网络课程设计ping工具.docx_第9页
第9页 / 共21页
计算机网络课程设计ping工具.docx_第10页
第10页 / 共21页
计算机网络课程设计ping工具.docx_第11页
第11页 / 共21页
计算机网络课程设计ping工具.docx_第12页
第12页 / 共21页
计算机网络课程设计ping工具.docx_第13页
第13页 / 共21页
计算机网络课程设计ping工具.docx_第14页
第14页 / 共21页
计算机网络课程设计ping工具.docx_第15页
第15页 / 共21页
计算机网络课程设计ping工具.docx_第16页
第16页 / 共21页
计算机网络课程设计ping工具.docx_第17页
第17页 / 共21页
计算机网络课程设计ping工具.docx_第18页
第18页 / 共21页
计算机网络课程设计ping工具.docx_第19页
第19页 / 共21页
计算机网络课程设计ping工具.docx_第20页
第20页 / 共21页
亲,该文档总共21页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

计算机网络课程设计ping工具.docx

《计算机网络课程设计ping工具.docx》由会员分享,可在线阅读,更多相关《计算机网络课程设计ping工具.docx(21页珍藏版)》请在冰点文库上搜索。

计算机网络课程设计ping工具.docx

计算机网络课程设计ping工具

摘要

关键词:

PING命令,IP/ICMP协议,SOCKET编程

摘要:

本课程设计包含了PING程序设计应用

其中PING程序设计使用了RAW模式的SOCKET编程,程序使用ICMP的封装机制,通过IP协议来工作。

本设计包括了具体设计任务,基本思路及所涉及的相关理论,设计流程图,调试过程中出现的问题及相应解决办法,实验运行结果,核心程序,个人体会及建议等。

概要设计

1.1题目的内容与要求

内容:

写一个程序,取代Windows下的Ping命令,可以Ping指定主机、一批主机,并以图形显示输出结果。

1.2总体结构

本程序主要分为四个模块(功能模块图见图1.1):

初始化模块,功能控制模块,数据报解读模块,Ping测试模块。

图1.1功能模块图

初始化模块:

该模块用于定义及初始化各个全局变量,为winsock加载winsock体。

功能控制模块:

该模块是被其他模块调用,其功能包括解析参数、计算ICMP数据报文检验和、清除SOCKET,ICMP包数据以及接受缓冲区。

数据报解读模块:

数据报解析模块提供了解读IP选项和解读ICMP报文的功能。

Ping测试模块:

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

详细设计

2.1Ping主模块

Ping()函数是本程序的核心部分,它基本是调用其他模块的函数来实现最终功能,其主要布骤包括:

定义及初始化各个全局变量、打开socket动态库、设置接收和发送超时值、域名地址解析、分配内存、创建及初始化ICMP报文、发送ICMP请求报文、接收ICMP应答报文以及解读应答报文和输出Ping结果,最后释放占用的资源其流程如图所示。

先主要考虑实现ping单一主机的情况,当ping同一网段内的多台主机时只须循环调用ping单一主机时的情况即可

图2.1主模块流程图

2.2功能控制模块

功能控制模块主要是为其他模块提供可调用的函数,该模块主要包括参数获取功能、计算ICMP数据报文检验和、清除SOCKET,ICMP包数据以及接受缓冲区、占用资源释放功能和显示用尸帮助功能。

该模块一共包含三个函数来实现。

,流程如图2.2所示。

图2.2功能控制模块

 

1.2基本思路及所涉及的相关理论

1.2.1、设计基本思路

在PING的工作原理下,PING程序基于ICMP,使用ICMP的回送请求和回送应答来工作。

为了实现直接对IP和ICMP包进行操作,设计采用RAW模式的SOCKET编程,实现网络连通性的测试,探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。

当传送IP数据包发生错误,ICMP协议将会把错误信息封包,然后传送回给主机。

PING程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。

1.2.2、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程序来计算间隔时间,并计算有多少个包被送达。

用户就可以判断网络大致的情况。

1.2.3、RAW模式的SOCKET编程

 WindowsSockets规范以U.C.Berkeley大学BSDUNIX中流行的Socket接口为范例定义了一套MicorosoftWindows下网络编程接口。

它不仅包含了人们所熟悉的BerkeleySocket风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。

 WindowsSockets规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵守。

此外,在一个特定版本Windows的基础上,WindowsSockets也定义了一个二进制接口(ABI),以此来保证应用WindowsSocketsAPI的应用程序能够在任何网络软件供应商的符合WindowsSockets协议的实现上工作。

因此这份规范定义了应用程序开发者能够使用,并且网络软件供应商能够实现的一套库函数调用和相关语义。

  任何能够与WindowsSockets兼容实现协同工作的应用程序就被认为是具有WindowsSockets接口。

我们称这种应用程序为WindowsSockets应用程序。

WindowsSockets规范定义并记录了如何使用API与Internet协议族(IPS,通常我们指的是TCP/IP)连接,尤其要指出的是所有的WindowsSockets实现都支持流套接口和数据报套接口.

   应用程序调用WindowsSockets的API实现相互之间的通讯。

WindowsSockets又利用下层的网络通讯协议功能和操作系统调用实现实际的通讯工作。

程序详细设计说明

<1>初始化winsock2网络环境

WSADATAwsa;

if(WSAStartup(MAKEWORD(2,2),&wsa)!

=0)

{

cerr<<"\n初始化WinSock2DLL失败\n"

<<"errorcode:

"<

return-1;

}

<2>//将命令行参数转换为IP地址

u_longulDestIP=inet_addr(argv[2]);

if(ulDestIP==INADDR_NONE)

{

//转换不成功时按域名解析

hostent*pHostent=gethostbyname(argv[2]);

if(pHostent)

{

ulDestIP=(*(in_addr*)pHostent->h_addr).s_addr;

//输出屏幕信息

cout<<"\nping"<

}

else//解析主机名失败

{

cerr<<"\n解析主机名"<

"<<'\n'

<<"errorcode:

"<

WSACleanup();

return-1;

}

}

else

{

//输出屏幕信息

cout<<"ping主机"<

}

<3>填充目的Socket地址

sockaddr_indestSockAddr;

ZeroMemory(&destSockAddr,sizeof(sockaddr_in));

destSockAddr.sin_family=AF_INET;

destSockAddr.sin_addr.s_addr=ulDestIP;

<4>创建RawSocket

SOCKETsockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);

if(sockRaw==INVALID_SOCKET)

{

cerr<<"\n创建rawsocket失败\n";

WSACleanup();

return-1;

}

<5>设置端口属性

intiTimeout=DEF_ICMP_TIMEOUT;

if(setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&iTimeout,sizeof(iTimeout))==SOCKET_ERROR)

{

cerr<<"\n设置发送时间超时失败\n";

closesocket(sockRaw);

WSACleanup();

return-1;

}

if(setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&iTimeout,sizeof(iTimeout))==SOCKET_ERROR)

{

cerr<<"\n设置接收时间超时失败\n";

closesocket(sockRaw);

WSACleanup();

return-1;

}

<6>创建ICPM包发送缓冲区和接收缓冲区

charIcmpSendBuf[sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE];

memset(IcmpSendBuf,0,sizeof(IcmpSendBuf));

charIcmpRecvBuf[MAX_ICMP_PACKET_SIZE];

memset(IcmpRecvBuf,0,sizeof(IcmpRecvBuf));

<7>填充待发送的ICMP包

ICMP_HEADER*pIcmpHeader=(ICMP_HEADER*)IcmpSendBuf;pIcmpHeader->type=ICMP_ECHO_REQUEST;//类型为请求回显pIcmpHeader->code=0;//代码字段为0

pIcmpHeader->id=(USHORT)GetCurrentProcessId();//ID字段为当前进程号

USHORTusSeqNo=0;

//以默认大小填充数据字段

memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE);

<7>发送ICMP数据报

if(sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,

(sockaddr*)&destSockAddr,sizeof(destSockAddr)==SOCKET_ERROR

{

//如果目的主机不可达则直接退出

if(WSAGetLastError()==WSAEHOSTUNREACH)

cout<<"发送失败:

"<

closesocket(sockRaw);

WSACleanup();

return0;

}

<8>接收ICMP数据报

while

(1)

{

iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(sockaddr*)&from,&iFromLen);

if(iReadDataLen!

=SOCKET_ERROR)//有数据包到达

{

if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen,

stDecodeResult,ittl))

{

if(stDecodeResult.dwIPaddr.s_addr==destSockAddr.sin_addr.s_addr)

{

Recived++;

cout<<"Replyfrom"<

stDecodeResult.dwRoundTripTime=GetTickCount()-stDecodeResult.dwRoundTripTime;

//统计传输时间

SumTripTime+=stDecodeResult.dwRoundTripTime;

if(Recived==1){MaxTripTime=MinTripTime=stDecodeResult.dwRoundTripTime;}

else

{

if(stDecodeResult.dwRoundTripTime>MaxTripTime)MaxTripTime=stDecodeResult.dwRoundTripTime;

if(stDecodeResult.dwRoundTripTime

}

//输出本次传输时间

if(stDecodeResult.dwRoundTripTime)

cout<<":

time="<

else

cout<<":

time"<<"<1"<<"ms";

cout<<"TTl="<

break;

}

else

{

cout<<"Requesttimedout.";

}

}

}

elseif(WSAGetLastError()==WSAETIMEDOUT)//接收超时

{

cout<<"Requesttimedout."<

break;

}

else

{

cerr<<"\n接收数据失败!

\n"

<<"errorcode:

"<

closesocket(sockRaw);

WSACleanup();

return-1;

}

<9>定义头类型文件

#include"StdAfx.h"

typedefstruct

{

unsignedcharhdr_len:

4;//lengthoftheheader

unsignedcharversion:

4;//versionofIP

unsignedchartos;//typeofservice

unsignedshorttotal_len;//totallengthofthepacket

unsignedshortidentifier;//uniqueidentifier

unsignedshortfrag_and_flags;//flags

unsignedcharttl;//timetolive

unsignedcharprotocol;//protocol(TCP,UDPetc)

unsignedshortchecksum;//IPchecksum

unsignedlongsourceIP;//sourceIPaddress

unsignedlongdestIP;//destinationIPaddress

}IP_HEADER;

//ICMP数据报头

typedefstruct

{

BYTEtype;//8位类型

BYTEcode;//8位代码

USHORTcksum;//16位校验和

USHORTid;//16位标识符

USHORTseq;//16位序列号

}ICMP_HEADER;

//解码结果

typedefstruct

{

USHORTusSeqNo;//包序列号

DWORDdwRoundTripTime;//往返时间

in_addrdwIPaddr;//对端IP地址

}DECODE_RESULT;

//线程参数

structThread_Param

{

charIPaddr1[20];

charIPaddr2[20];

};

typedefstructThread_ParamThread_Param;

typedefstructThread_Param*pThread_Param;

//ICMP类型字段

constBYTEICMP_ECHO_REQUEST=8;//请求回显

constBYTEICMP_ECHO_REPLY=0;//回显应答

constBYTEICMP_TIMEOUT=11;//传输超时

constDWORDDEF_ICMP_TIMEOUT=50;//默认超时时间,单位ms

constintDEF_ICMP_DATA_SIZE=32;//默认ICMP数据部分长度

constintMAX_ICMP_PACKET_SIZE=1024;//最大ICMP数据报的大小

constintDEF_MAX_HOP=30;//最大跳站数

 

USHORTGenerateChecksum(USHORT*pBuf,intiSize);

BOOLDecodeIcmpResponse(char*pBuf,intiPacketSize,DECODE_RESULT&stDecodeResult,unsignedchar&ittl);

DWORDSingle_ThreadProc(LPVOIDlpParameter);

DWORDMulti_ThreadProc(LPVOIDlpParameter);

 

classPing

{

public:

Ping();

~Ping();

voidAction_Clear();

voidSetMainHwnd(HWNDhwnd);

voidStart();

voidScanSingleHost(char*IPaddr1,char*IPaddr2);

voidScanMultiHost(char*IPaddr1,char*IPaddr2);

private:

HWNDmain_hwnd;

protected:

};

<10>输出窗口图形化设计

StatusWindow:

:

StatusWindow()

{

nID=0;

num_parts=1;

hStatusWin=NULL;

}

BOOLStatusWindow:

:

CreateStatus(HWNDhwnd,intnum_parts,int*Width,intnID)

{

this->nID=nID;

if(Width==NULL)

{

MessageBox(hwnd,TEXT("宽度数组不能为空!

"),TEXT("提示"),MB_ICONWARNING);

returnFALSE;

}

if(num_parts>=1&&num_parts<=255)

{

this->num_parts=num_parts;

}

else

{

MessageBox(hwnd,TEXT("分栏数范围(1-255)!

"),TEXT("提示"),MB_ICONWARNING);

returnFALSE;

}

hStatusWin=CreateStatusWindow(WS_CHILD|WS_VISIBLE,NULL,hwnd,nID);//IDC_STATUS需要在resource.h里面自己定义

if(hStatusWin==NULL)

{

MessageBox(hwnd,TEXT("创建状态栏失败!

"),TEXT("提示"),MB_ICONERROR);

returnFALSE;

}

BOOLresult=SendMessage(hStatusWin,SB_SETPARTS,(WPARAM)num_parts,(LPARAM)Width);

if(result==FALSE)

{

MessageBox(hwnd,TEXT("设置分栏操作失败!

"),TEXT("提示"),MB_ICONERROR);

returnresult;

}

returnTRUE;

}

StatusWindow:

:

~StatusWindow()

{

}

BOOLStatusWindow:

:

InsertItem(HWNDhwnd,intIndex_part,char*contents)

{

if(Index_part<0||Index_part>num_parts)

{

MessageBox(hwnd,TEXT("状态栏索引错误!

"),TEXT("提示"),MB_ICONWARNING);

returnFALSE;

}

if(contents==NULL)

{

MessageBox(hwnd,TEXT("内容不能为空!

"),TEXT("提示"),MB_ICONWARNING);

returnFALSE;

}

if(hStatusWin==NULL)

{

MessageBox(hwnd,TEXT("状态栏句柄为空!

"),TEXT("提示"),MB_ICONWARNING);

returnFALSE;

}

BOOLret=SendMessage(hStatusWin,SB_SETTEXT,(WPARAM)Index_part,(LPARAM)contents);

if(ret==FALSE)

{

MessageBox(hwnd,TEXT("状态栏插入文本操作失败!

"),TEXT("提示"),MB_ICONWARNING);

returnret;

}

returnTRUE;

}

HWNDStatusWindow:

:

GethStatus()

{

returnhStatusWin;

}

使用说明结果分析

在VC中运行程序后会出现如下图所示,提示你输入IP

当要pin

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

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

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2