收藏一个Ping的小工具类,可用于网络中检测目的设备是否在线
来源:互联网 发布:unity3d制作下雨特效 编辑:程序博客网 时间:2024/05/30 04:22
记不起在哪个项目中需要做一个检查设备在线状态的功能,可当时又没有设备的SDK可使用,网上找索很久,找到这款PING的小工具,简单适用,自己修改了一下,用起来超方便。 自己先攒起来再说。
[头文件]
#ifndef _PINGTOOL_H#define _PINGTOOL_H#include <winsock2.h> #include <iostream>#pragma comment( lib, "ws2_32.lib" ) class CPintTool{ #define ICMP_ECHO 8 //回应请求类型的ICMP消息类型 #define ICMP_ECHOREPLY 0 //回应答复型的ICMP消息类型 #define ICMP_MIN 8 // ICMP数据报最小长度 #define DEF_PACKET_SIZE 32 //默认数据报大小 #define DEF_PACKET_NUMBER 3 //发送数据报的个数 #define MAX_PACKET 1024 //最大ICMP数据报大小public: CPintTool(); ~CPintTool();public: bool pintTo( char* destIP );private: SOCKET sockRaw; int destlen, fromlen, bwrote, bread; sockaddr_in dest,from; char *icmp_data, *recvbuf; struct hostent *hp; unsigned short seq; //成员变量的定义 char *Ipdest; //目标主机的IP地址 int datasize; //ICMP消息的长度 //接收到的ICMP消息数,每收到一条ICMP消息就加1// static int icmpcount=0; int icmpcount; //IP头(20字节) struct IPHEAD { unsigned int headlength:4; // 4位头长度 unsigned int version:4; // 4位版本 unsigned char tos; // 8位服务类型 unsigned short totallength; // 16位总长 unsigned short ip_id; // 16位标识 unsigned short frag_and_flags; //3个一位标识加分段偏移 unsigned char ttl; //8位存活时间 unsigned char protocal; //8位协议类型 unsigned short ip_checksum; //16位头校验和 unsigned int sourceIP; //32位源IP地址 unsigned int destIP; //32位目标IP地址 }; // ICMP 头(12字节) struct ICMPHEAD { unsigned char type; //类型(0,8) unsigned char code; //代码(0) unsigned short icmp_checksum; //校验和 unsigned short icmp_id; //标识符 unsigned short seq; //序号 unsigned long timestamp; //时间戳 }; private: //成员函数的定义 //Fill_icmp_data函数:用于设置ICMP头部,填充ICMP消息 void Fill_icmp_data(char * icmp_data, int datasize); //DecodeICMPHEAD函数:接受数据时从IP头中获取ICMP消息 void DecodeICMPHEAD(char *recvbuf, int bread, sockaddr_in *from); //Checksum函数:用于求ICMP首部校验和 unsigned short Checksum(unsigned short *buffer, int size); //Usage函数:表示程序的功能 void Usage(char *progname);};#endif //_PINGTOOL_H
[CPP文件]
#include <stdafx.h>#include <iostream>#include "PingTool.h"using namespace std;CPintTool::CPintTool():icmp_data( NULL ),recvbuf( NULL ),hp( NULL ),seq( 0 ),sockRaw( INVALID_SOCKET ),datasize( DEF_PACKET_SIZE ) //数据包大小为DEF_PACKET_SIZE=32{ WSADATA wsaData; //启动winsock失败,输出错误提示信息 if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0) { cout<<"WSAStartup failed:"<<GetLastError(); cout<<endl; return; } destlen = sizeof(sockaddr_in); fromlen = sizeof(sockaddr_in);}CPintTool::~CPintTool(){ WSACleanup();}bool CPintTool::pintTo( char* destIP ){ Ipdest= destIP; //默认目的地址为:202.119.81.120 //创建套接字失败,输出错误信息提示 sockRaw = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED); if (sockRaw == INVALID_SOCKET) { cout<<"WSASocket() failed:"<<GetLastError(); cout<<endl; return false; } //设定发送数据时最长等待时间timeout=1000ms int timeout=1000; bread=setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)); if(bread==SOCKET_ERROR) { cout<<"setsockopt(SO_RCVTIMEO) failed:"<<WSAGetLastError(); cout<<endl; return false; } //设定接收数据时最长等待时间timeout=1000ms timeout=1000; bread=setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)); if(bread==SOCKET_ERROR) { cout<<"setsockopt(SO_SNDTIMEO) failed:"<<WSAGetLastError(); cout<<endl; return false; } //解析目的地址的名称 dest.sin_family=AF_INET; if(dest.sin_addr.s_addr=inet_addr(Ipdest)) { //inet_addr将IP地址转换成网络地址 if((hp=gethostbyname(Ipdest))!=NULL) { //gethostbyname主机信息 memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length); //复制内存 dest.sin_family=hp->h_addrtype; cout<<"dest.sin_addr="<<inet_ntoa(dest.sin_addr); cout<<endl<<'\n'; } else { cout<<"gethostbyname() failed:"<<WSAGetLastError(); cout<<endl; return false; } } //建立一个ICMP数据包 datasize+=sizeof(ICMPHEAD); //为要发送的数据申请内存空间,最大值为1024 icmp_data=new char[MAX_PACKET]; //为要接收的数据申请内存空间,最大值为1024 recvbuf=new char[MAX_PACKET]; //分配内存失败,输出提示信息 if(!icmp_data) { cout<<"new char[] failed:"<<WSAGetLastError(); cout<<endl; return false; } //将ICMP信息所在空间清零 memset(icmp_data,0,MAX_PACKET); //设置ICMP信息头部 Fill_icmp_data(icmp_data,datasize); //发送和接收数据,循环三次 icmpcount = 0; for(int i=0;i<3;i++) { //ICMP信息封装 ((ICMPHEAD*)icmp_data)->icmp_checksum=0; ((ICMPHEAD*)icmp_data)->timestamp = GetTickCount(); ((ICMPHEAD*)icmp_data)->seq=seq++; ((ICMPHEAD*)icmp_data)->icmp_checksum = Checksum((unsigned short*)icmp_data,datasize); //发送数据 bwrote = sendto(sockRaw,icmp_data,datasize,0, (sockaddr*)&dest,destlen); if (bwrote == SOCKET_ERROR) { if (WSAGetLastError() == WSAETIMEDOUT) { cout<<"Request timed out."<<endl; continue; } else { cout<<"sendto( ) failed:"<<WSAGetLastError(); cout<<endl; return false; } } //显示实际发送的字节数 cout<<"Pinging "<<inet_ntoa(dest.sin_addr)<<" with "; cout<<bwrote<<" bytes of data:"; cout<<endl; //接收数据 bread=recvfrom(sockRaw,recvbuf,MAX_PACKET,0, (sockaddr*)&from,&fromlen); if (bread == SOCKET_ERROR) { if (WSAGetLastError() == WSAETIMEDOUT) { cout<<"Request timed out."<<endl; continue; } cout<<"recvfrom() failed: "<<WSAGetLastError(); cout<<endl; return false; } //打开接收到的数据,从中提取ICMP头信息 DecodeICMPHEAD(recvbuf,bread,&from); //等待1s钟 Sleep(1000); } //输出发送的数据包数、接收的数据包数和丢失的数据包数 cout<<endl; cout<<"Ping statistics for "<<inet_ntoa(dest.sin_addr)<<":"<<endl; cout<<" Packets:sent=4,"; cout<<"Received="<<icmpcount; cout<<",Lost="<<DEF_PACKET_NUMBER-icmpcount; cout<<"("<<((float)(DEF_PACKET_NUMBER-icmpcount)/DEF_PACKET_NUMBER)*100; cout<<"%loss)"; cout<<endl; //释放资源,关闭winsock if(sockRaw!=INVALID_SOCKET) closesocket(sockRaw); delete[] recvbuf; delete[] icmp_data; if ( icmpcount == 0 ) return false; return true;}//Fill_icmp_data函数:用于设置ICMP头部,填充ICMP消息void CPintTool::Fill_icmp_data(char * icmp_data, int datasize){ ICMPHEAD *icmphead=NULL; char *datapart=NULL; icmphead = (ICMPHEAD*)icmp_data; icmphead->type = ICMP_ECHO; //ICMP_ECHO=8 icmphead->code = 0; //类型为8,代码为0,表示回应请求 icmphead->icmp_checksum = 0; icmphead->icmp_id = (unsigned short)GetCurrentProcessId(); datapart = icmp_data + sizeof(ICMPHEAD);//具体内容的首地址指针 //初始化数据包内容部分 for( int i=0;i < (datasize-sizeof(ICMPHEAD)); i++,datapart++ ) *datapart=0;} //DecodeICMPHEAD函数:接受数据时从IP头中获取ICMP消息void CPintTool::DecodeICMPHEAD(char *recvbuf, int bread, sockaddr_in *from) { IPHEAD *iphead=NULL; ICMPHEAD *icmphead=NULL; DWORD tick; unsigned short iphdrlen; iphead = (IPHEAD *)recvbuf; //32位字的个数乘以4即字节个数 iphdrlen = (iphead->headlength) * 4 ; //获取操作系统启动至今所经过的时间(ms) tick=GetTickCount(); if (bread < (iphdrlen + ICMP_MIN)) { cout<<"Too few bytes from: "<<inet_ntoa(from->sin_addr); cout<<endl; } icmphead = (ICMPHEAD*)(recvbuf + iphdrlen); //ICMP消息始于IP头之后 //若ICMP消息类型并非查询,则输出相应信息类型 if (icmphead->type != ICMP_ECHOREPLY) { cout<<"nonecho type "<<int(icmphead->type)<<" received"; cout<<endl; } //确认收到的应答ICMP消息是否是对发送出去的消息的回应 //若其表示与当前进程不符,则输出出错信息 if (icmphead->icmp_id != (unsigned short)GetCurrentProcessId()) { cout<<"It's someone else's packet!"<<endl; return; } //输出收到信息的内容:主机地址,icmp消息序号,回应时间,存活时间 cout<<"Reply from "<<inet_ntoa(from->sin_addr); cout<<" bytes="<<bread-iphdrlen; cout<<" time: "<<GetTickCount()-icmphead->timestamp<<" ms "; cout<<" seq="<<icmphead->seq; cout<<endl; icmpcount++;} //Checksum函数:用于求ICMP首部校验和unsigned short CPintTool::Checksum(unsigned short *buffer, int size) { unsigned long cksum=0; //设校验和初值为0 while(size >1) { cksum+=*buffer++; //求各个16位数字之和 size -=sizeof(unsigned short); } if(size) { cksum += *(unsigned char*)buffer; } cksum = (cksum >> 16) + (cksum & 0xffff); //高位与低位相加 cksum += (cksum >>16); //加上进位 return (unsigned short)(~cksum); //取反得到校验和} //Usage函数:表示程序的功能void CPintTool::Usage(char *progname){ cout<<"Usage:"<<progname<<" <host>"<<endl; cout<<" host remote machine to Ping"<<endl; cout<<endl;}
[用法:]
#include "stdafx.h"#include <iostream>#include "PingTool.h"int _tmain(int argc, _TCHAR* argv[]){ CPintTool pingT; char* ipdest = "192.168.3.254"; bool boo = pingT.pintTo( ipdest ); if ( boo )
{
<span style="white-space:pre"></span>std::cout << " 目标地址可达! " << std::endl;
}
else
{
<span style="white-space:pre"></span>std::cout << " 目标地址不可达!!! " << std::endl;
} return 0;}
0 0
- 收藏一个Ping的小工具类,可用于网络中检测目的设备是否在线
- Qt检测设备是否在线(Ping)
- 一个快速批量查询快递物流数据的小工具,可用于快递物流跟踪
- 一个值得收藏的小工具
- Android中用于检测当前手机网络是否可用
- 检测网络是否可用
- 一个小工具类
- GUIDReporter:辅助调试USB设备的一个小工具
- Android笔记---Android网络检测小工具
- C# Ping类的例子,可用于测试网络,主机响应时间等。
- C# Ping类的例子,可用于测试网络,主机响应时间等
- C# Ping类的例子,可用于测试网络,主机响应时间等。
- 程序小工具类方面的url收藏
- 无处不在的网络小工具
- Android--用ping的方法判断当前网络是否可用
- 有用的小工具收藏(1)
- 利用ping来检测设备在线
- 一个倒计时的小工具
- HDU1004(C++map的用法)
- appium环境搭建
- 工作计划
- 配置tnsping跟踪来诊断Oracle Net连接
- cocos2dx播放音乐
- 收藏一个Ping的小工具类,可用于网络中检测目的设备是否在线
- ubuntu下的mysql不支持中文,修改方法;
- C语言入门----输出语句
- codeforces 76A Gift 最小生成树
- [leetcode] 139. Word Break 解题报告
- 如何获取一个范围内的随机整数
- Python中*args 和**kwargs的用法探讨
- 进击的KFC:OC(五): 字典、集、数组排序
- 在java中输入某年某月,判断这一天是是这一年的第多少天