1、1.2.1、设计基本思路在PING的工作原理下,PING程序基于ICMP,使用ICMP的回送请求和回送应答来工作。为了实现直接对IP和ICMP包进行操作,设计采用RAW模式的SOCKET编程,实现网络连通性的测试,探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。当传送IP数据包发生错误,ICMP协议将会把错误信息封包,然后传送回给主机。PING程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。1.2.2、PING的工作原理PING 程序是用来探测主机到主机之间是否可通信,如果不能ping到某台主机,表明不能和这台主机建立连接。pi
2、ng 使用的是ICMP协议,它发送ICMP回送请求消息给目的主机。ICMP协议规定:目的主机必须返回ICMP回送应答消息给源主机。如果源主机在一定时间内收到应答,则认为主机可达。ICMP协议通过IP协议发送的,IP协议是一种无连接的,不可靠的数据包协议。因此,保证数据送达的工作应该由其他的模块来完成。其中一个重要的模块就是ICMP(网络控制报文)协议。当传送IP数据包发生错误比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机。给主机一个处理错误的机会,这也就是为什么说建立在IP层以上的协议是可能做到安全的原因。ICMP数据包由8bit的错误类型和8bit的代码和1
3、6bit的校验和组成。而前 16bit就组成了ICMP所要传递的信息。PING利用ICMP协议包来侦测另一个主机是否可达。原理是用类型码为0的ICMP发请求,受到请求的主机则用类型码为8的ICMP回应。ping程序来计算间隔时间,并计算有多少个包被送达。用户就可以判断网络大致的情况。1.2.3、RAW模式的SOCKET编程 Windows Sockets规范以U.C. Berkeley大学BSD UNIX中流行的Socket接口为范例定义了一套Micorosoft Windows下网络编程接口。它不仅包含了人们所熟悉的Berkeley Socket风格的库函数;也包含了一组针对Windows的
4、扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。 Windows Sockets规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵守。此外,在一个特定版本Windows的基础上,Windows Sockets也定义了一个二进制接口(ABI),以此来保证应用Windows Sockets API的应用程序能够在任何网络软件供应商的符合Windows Sockets协议的实现上工作。因此这份规范定义了应用程序开发者能够使用,并且网络软件供应商能够实现的一套库函数调用和相关语义。 任何能够与Windows Sockets兼容实现协同工作的应用程序就被
5、认为是具有Windows Sockets接口。我们称这种应用程序为Windows Sockets应用程序。Windows Sockets规范定义并记录了如何使用API与Internet协议族(IPS,通常我们指的是TCP/IP)连接,尤其要指出的是所有的Windows Sockets实现都支持流套接口和数据报套接口. 应用程序调用Windows Sockets的API实现相互之间的通讯。Windows Sockets又利用下层的网络通讯协议功能和操作系统调用实现实际的通讯工作。程序详细设计说明初始化winsock2 网络环境 WSADATA wsa; if (WSAStartup(MAKEWO
6、RD(2, 2), &wsa) != 0) cerr n初始化 WinSock2 DLL失败n error code: WSAGetLastError() /将命令行参数转换为IP地址 u_long ulDestIP = inet_addr(argv2); if (ulDestIP = INADDR_NONE) /转换不成功时按域名解析 hostent* pHostent = gethostbyname(argv2); if (pHostent) ulDestIP=(*(in_addr*)pHostent-h_addr).s_addr; /输出屏幕信息 cout n ping argv2 in
7、et_ntoa(*(in_addr*)(&ulDestIP) ; else /解析主机名失败 cerr n解析主机名 argv2失败! nerrorcode: WSACleanup(); return -1; else /输出屏幕信息 cout 填充目的Socket地址 sockaddr_in destSockAddr;ZeroMemory(&destSockAddr, sizeof(sockaddr_in); destSockAddr.sin_family = AF_INET; destSockAddr.sin_addr.s_addr = ulDestIP;4创建Raw Socket SOC
8、KET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED); if (sockRaw = INVALID_SOCKET)n创建 raw socket失败n; WSACleanup();5设置端口属性 int iTimeout = DEF_ICMP_TIMEOUT; if(setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeout, sizeof(iTimeout) = SOCKET_ERROR)n设置发送时间超时失败n
9、 closesocket(sockRaw); if(setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO, (char*)&n设置接收时间超时失败n ;6创建ICPM包发送缓冲区和接收缓冲区 char IcmpSendBufsizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE; memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf); char IcmpRecvBufMAX_ICMP_PACKET_SIZE; memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf);7填充待发送
10、的ICMP包ICMP_HEADER* pIcmpHeader = (ICMP_HEADER*)IcmpSendBuf; pIcmpHeader-type = ICMP_ECHO_REQUEST; /类型为请求回显pIcmpHeader-code = 0; /代码字段为0pIcmpHeader-id = (USHORT)GetCurrentProcessId(); /ID字段为当前进程号USHORT usSeqNo = 0;/以默认大小填充数据字段memset(IcmpSendBuf+sizeof(ICMP_HEADER),E, DEF_ICMP_DATA_SIZE);发送ICMP数据报 if
11、(sendto(sockRaw, IcmpSendBuf, sizeof(IcmpSendBuf), 0, (sockaddr*)&destSockAddr,sizeof(destSockAddr)= SOCKET_ERROR /如果目的主机不可达则直接退出 if (WSAGetLastError() = WSAEHOSTUNREACH)发送失败: return 0;8接收ICMP数据报 while(1) iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf, MAX_ICMP_PACKET_SIZE, 0, (sockaddr*)&from, &iFromLen
12、); if (iReadDataLen != SOCKET_ERROR) /有数据包到达 if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen, stDecodeResult,ittl ) if(stDecodeResult.dwIPaddr.s_addr= destSockAddr.sin_addr.s_addr) Recived+;Reply from inet_ntoa(stDecodeResult.dwIPaddr); stDecodeResult.dwRoundTripTime= GetTickCount()-stDecodeResult.dw
13、RoundTripTime; /统计传输时间 SumTripTime+=stDecodeResult.dwRoundTripTime; if(Recived=1) MaxTripTime=MinTripTime=stDecodeResult.dwRoundTripTi me; else if(stDecodeResult.dwRoundTripTimeMaxTripTime) MaxTripTime=stDecodeResult.dwRoundTripTime; if(stDecodeResult.dwRoundTripTimeMinTripTime) MinTripTime=stDecode
14、Result.dwRoundTripTime; /输出本次传输时间 if (stDecodeResult.dwRoundTripTime) cout :time=stDecodeResult.dwRoundTripTime ms else cout time1ms cout TTl=int(ittl) break; elseRequest timed out. else if (WSAGetLastError() = WSAETIMEDOUT) /接收超时 break; cerr n接收数据失败!n 定义头类型文件#include StdAfx.htypedef struct unsigned
15、 char hdr_len :4; / length of the header unsigned char version : / version of IP unsigned char tos; / type of service unsigned short total_len; / total length of the packet unsigned short identifier; / unique identifier unsigned short frag_and_flags; / flags unsigned char ttl; / time to live unsigne
16、d char protocol; / protocol (TCP, UDP etc) unsigned short checksum; / IP checksum unsigned long sourceIP; / source IP address unsigned long destIP; / destination IP address IP_HEADER;/ICMP数据报头 BYTE type; /8位类型 BYTE code; /8位代码 USHORT cksum; /16位校验和 USHORT id; /16位标识符 USHORT seq; /16位序列号 ICMP_HEADER;
17、/解码结果 USHORT usSeqNo; /包序列号 DWORD dwRoundTripTime; /往返时间 in_addr dwIPaddr; /对端IP地址 DECODE_RESULT;/线程参数struct Thread_Param char IPaddr120; char IPaddr220;typedef struct Thread_Param Thread_Param;typedef struct Thread_Param * pThread_Param;/ICMP类型字段const BYTE ICMP_ECHO_REQUEST = 8; /请求回显const BYTE ICM
18、P_ECHO_REPLY = 0; /回显应答const BYTE ICMP_TIMEOUT = 11; /传输超时const DWORD DEF_ICMP_TIMEOUT = 50; /默认超时时间,单位msconst int DEF_ICMP_DATA_SIZE = 32; /默认ICMP数据部分长度const int MAX_ICMP_PACKET_SIZE = 1024; /最大ICMP数据报的大小const int DEF_MAX_HOP = 30; /最大跳站数USHORT GenerateChecksum(USHORT* pBuf,int iSize);BOOL DecodeIc
19、mpResponse(char* pBuf,int iPacketSize,DECODE_RESULT& stDecodeResult,unsigned char &ittl);DWORD Single_ThreadProc(LPVOID lpParameter);DWORD Multi_ThreadProc(LPVOID lpParameter);class Ping public: Ping(); Ping(); void Action_Clear(); void SetMainHwnd(HWND hwnd); void Start(); void ScanSingleHost(char
20、*IPaddr1,char *IPaddr2); void ScanMultiHost(char *IPaddr1,char *IPaddr2); private: HWND main_hwnd; protected:10输出窗口图形化设计StatusWindow : StatusWindow() nID = 0; num_parts = 1; hStatusWin = NULL;BOOL StatusWindow : CreateStatus(HWND hwnd,int num_parts,int *Width,int nID) this-nID = nID; if(Width = NULL
21、) MessageBox(hwnd,TEXT(宽度数组不能为空!),TEXT(提示),MB_ICONWARNING); return FALSE; if(num_parts = 1& num_parts num_parts = num_parts;分栏数范围(1-255)! hStatusWin = CreateStatusWindow(WS_CHILD|WS_VISIBLE,NULL,hwnd,nID);/IDC_STATUS需要在resource.h里面自己定义 if(hStatusWin = NULL)创建状态栏失败!),MB_ICONERROR); BOOL result = Send
22、Message(hStatusWin,SB_SETPARTS,(WPARAM)num_parts,(LPARAM)Width); if(result = FALSE)设置分栏操作失败! return result; return TRUE; StatusWindow() InsertItem(HWND hwnd,int Index_part,char *contents) if(Index_part num_parts)状态栏索引错误! if(contents = NULL)内容不能为空!状态栏句柄为空! BOOL ret = SendMessage(hStatusWin,SB_SETTEXT,(WPARAM)Index_part,(LPARAM)contents); if(ret = FALSE)状态栏插入文本操作失败! return ret;HWND StatusWindow : GethStatus() return hStatusWin;使用说明结果分析在VC中运行程序后会出现如下图所示,提示你输入IP当要pin
copyright@ 2008-2023 冰点文库 网站版权所有
经营许可证编号:鄂ICP备19020893号-2