Windows下基于Qt用c++实现ping
来源:互联网 发布:什么是核函数 知乎 编辑:程序博客网 时间:2024/06/05 12:45
Windows下基于Qt用c++实现ping
1、代码来源
此份ping的源码来自于vc6对应msdn中。自己稍做修改,然后成了现在这个版本。
2、winsock与winsock2
windows下socket有2个版本,分别对应2个不同的头文件 winsock.h 和 winsock2.h 。对应WSAStartup第一个参数是MAKEWORD(1,1)还是MAKEWORD(1,2)。
这俩有啥不同呢。。。。还没具体研究过。。。。不过个人感觉winsock更通用,因为winsock2里面socket都可以用WSASocket来创建。
而偶个人感觉,用socket s=socket(AF_NET…….)的方式创建更通用。所以很执拗的使用winsock版本,抛弃winsock2。因为socket是POSIX通用的接口。用这个,跨平台移植工作量更小。
然后,winsock2是基本前向兼容winsock的。为啥说基本,因为偶没具体深入研究证实过。。。我所知道的其中一个证据是winsock与winsock2同处于一个dll文件中,WS2_32.dll。但是通过不同的头文件可以对应不同的版本。或者说winsock.h是为了保证原有代码可用的一个措施。。。。。。。。
3、Qt工程文件配置
TEMPLATE = appCONFIG += console c++11CONFIG -= app_bundleCONFIG -= qtSOURCES += main.cpp \ Pinger.cppHEADERS += \ Pinger.h#Qt下导入winsock。2个版本的都在这里面了。LIBS += -lWS2_32
4、类头文件
#ifndef PINGER_H#define PINGER_H#include <windows.h>#include <winsock.h>#include <string>#pragma pack(push)#pragma pack(1)struct IpHead{ unsigned int uiHeadLen:4; ///<头部长度 unsigned int uiVersion:4; ///<版本 unsigned char ucTos; ///<服务类型,type of service unsigned short usTotalLen; ///<总长度 unsigned short usIpId; ///<标识 unsigned short usFlags; ///<3位标志+13位片偏移 unsigned char ucTtl; ///<TTL,time to live unsigned char ucProtocol; ///<协议 unsigned short usCheckSum; ///<首部总校验和 unsigned int uiSrcIP; ///<源ip unsigned int uiDstIP; ///<目的ip};struct IcmpHead{ unsigned char ucType; ///<类型 unsigned char ucCode; ///<代码 unsigned short ususIcmpChkSum; ///<校验和 unsigned short usIcmpId; ///<id unsigned char usSeq; ///<序号 unsigned long ulTimeStamp; ///<时间戳};#pragma pack(pop)#define DEF_PACKET_SIZE 32#define ECHO_REQUEST 8#define ECHO_REPLY 0#define ICMP_ECHOREPLY 0#define ICMP_MIN sizeof(IcmpHead)#define ICMP_ECHO 8class Pinger{public: Pinger(); virtual ~Pinger(); /** * @brief ping ping指定ip地址 * @param dstIP 目的ip,不能包含空格等非法字符 * @param packNum 一共ping几包 * @param sndTime 发送超时时间,单位毫秒 * @param rcvTime 接收超时时间,单位毫秒 * @return 成功ping通的包数,大于0表示ping通 */ int ping(const char* dstIP, const int& packNum, const int &sndTime, const int &rcvTime); /** * @brief getTips 获取提示信息 * @return 提示信息 */ std::string getTips() const {return m_strTips_;}protected: /** * @brief checkSum 计算校验和 * @param buf 待计算缓冲区 * @param wordCnt 字个数 * @return 校验和 */ unsigned short checkSum(const WORD *buf, const int &wordCnt); /** * @brief decodeIcmpHead 解析icmp头 * @param rcvBuf 头部缓冲区 * @param bread 字节数 * @param from 来源ip地址 * @return 0表示正常,其他见错误码EnErrCode */ int decodeIcmpHead(char *rcvBuf,unsigned int bread,sockaddr_in *from); /** * @brief fillImcpData 填充icmp数据 * @param icmpData 缓冲区 * @param byteCnt 缓冲区长度 */ void fillImcpData(char *icmpData, int byteCnt); std::string m_strTips_; ///<提示信息private: enum EnErrCode{ EnOK, EnNullPtr, EnBadData, EnInvalidIp, EnSockErr, }; unsigned int m_uiId__; ///<当前对象id计数 static unsigned int m_uiCnt__; ///<总对象创建数计数};#endif // PINGER_H
5、类源文件
#include "Pinger.h"unsigned int Pinger::m_uiCnt__=0;Pinger::Pinger(){ WSADATA data; char tips[256]={0}; snprintf(tips,sizeof(tips),"wsa init ret %d,errCode:%d.\n",WSAStartup(MAKEWORD(1,2),&data),WSAGetLastError()); m_strTips_+=tips; m_uiId__=m_uiCnt__++;}Pinger::~Pinger(){ WSACleanup();}int Pinger::ping(const char *dstIP, const int& packNum, const int& sndTime, const int& rcvTime){ int nRet=0; m_strTips_+="ping tips.\n"; char tips[256]={0}; SOCKET sockRaw=INVALID_SOCKET; struct sockaddr_in dest,from; unsigned short seq_no=0; int bread,datasize; int fromlen=sizeof(from); char icmp_data[1024]={0}; char rcvbuf[1024]={0}; unsigned int addr = inet_addr(dstIP); int timeout=sndTime; if(INADDR_NONE ==addr){ m_strTips_+="invalid dstip,"; m_strTips_+=dstIP; return EnInvalidIp; } sockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); if(INVALID_SOCKET == sockRaw){ snprintf(tips,sizeof(tips),"create sock failed,errcode:%d\n",WSAGetLastError()); m_strTips_+=tips; return EnSockErr; } //set send time-out val bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout)); snprintf(tips,sizeof(tips),"set send time-out %d,ret:%d,errCode:%d.",timeout,bread,WSAGetLastError()); m_strTips_+=tips; //set recv time-out val timeout=rcvTime; bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(timeout)); snprintf(tips,sizeof(tips),"set recv time-out %d,ret:%d,errCode:%d.",timeout,bread,WSAGetLastError()); m_strTips_+=tips; memset(&dest,0,sizeof(dest)); dest.sin_addr.s_addr=addr; dest.sin_family= AF_INET; datasize=DEF_PACKET_SIZE+sizeof(IcmpHead); m_strTips_+="\n"; for(int i=packNum;i>0;i--){ fillIcmpData(icmp_data,datasize); ((IcmpHead*)icmp_data)->ulTimeStamp=GetTickCount(); ((IcmpHead*)icmp_data)->usSeq=seq_no++; ((IcmpHead*)icmp_data)->ususIcmpChkSum=checkSum((WORD*)icmp_data,datasize); int bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest)); snprintf(tips,sizeof(tips),"send,ret:%d,sndErrCode:%d,",bwrote,WSAGetLastError()); m_strTips_+=tips; bread = recvfrom(sockRaw,rcvbuf,sizeof(rcvbuf),0,(struct sockaddr*)&from,&fromlen); snprintf(tips,sizeof(tips),"recv,ret:%d,rcvErrCode:%d.",bread,WSAGetLastError()); m_strTips_+=tips; if(bread>0){ decodeIcmpHead(rcvbuf,bread,&from); nRet++; } Sleep(200); m_strTips_+="\n"; } if(INVALID_SOCKET != sockRaw){ int clsRet= closesocket(sockRaw); snprintf(tips,sizeof(tips),"close sock:%u,ret:%d,errCode:%d\n",sockRaw,clsRet,WSAGetLastError()); m_strTips_+=tips; } return nRet;}unsigned short Pinger::checkSum(const WORD *buf, const int& wordCnt){ WORD wChkSum=0; for(int i = wordCnt;i>0;i--){ wChkSum+=*buf++; } wChkSum=(wChkSum>>16)+(wChkSum & 0xffff); wChkSum+=(wChkSum>>16); return (WORD)(~wChkSum);}int Pinger::decodeIcmpHead(char *rcvBuf, const unsigned int bread, const sockaddr_in *from){ if(NULL == rcvBuf || NULL == from){ m_strTips_+="decode imcp head encounter null ptr.\n"; return EnNullPtr; } char tips[256]={0}; IpHead *ipHead=(IpHead*)rcvBuf; IcmpHead *icmpHead=NULL; WORD wIpHeadLen=ipHead->uiHeadLen*4; if(bread<(wIpHeadLen+ICMP_MIN)){ snprintf(tips,sizeof(tips),"too few bytes from %s\n",inet_ntoa((from->sin_addr))); m_strTips_+=tips; return EnBadData; } icmpHead=(IcmpHead*)(rcvBuf+wIpHeadLen); if(icmpHead->ucType != ICMP_ECHOREPLY){ snprintf(tips,sizeof(tips),"no echo tpye %d rcved.\n",int(icmpHead->ucType)); m_strTips_+=tips; } if(icmpHead->usIcmpId != m_uiId__){ snprintf(tips,sizeof(tips),"some one's pack. realId:%u,myId:%u.\n",icmpHead->usIcmpId,m_uiId__); m_strTips_+=tips; } snprintf(tips,sizeof(tips),"reply from %s, %u bytes, time:%u ms, seq:%d, id:%u.\n",inet_ntoa(from->sin_addr), bread-wIpHeadLen,GetTickCount()-icmpHead->ulTimeStamp,icmpHead->usSeq,icmpHead->usIcmpId); m_strTips_+=tips; return 0;}void Pinger::fillIcmpData(char *icmpData, const int &byteCnt){ if(NULL == icmpData){ m_strTips_+="fill icmp data encounter null ptr.\n"; return; } IcmpHead *icmpHead=(IcmpHead*)icmpData; char* dataPart=NULL; icmpHead->ucType=ICMP_ECHO; icmpHead->ucCode=0; icmpHead->ususIcmpChkSum=0; icmpHead->usIcmpId=m_uiId__; dataPart=icmpData+sizeof(IcmpHead); memset(dataPart,0,byteCnt-sizeof(IcmpHead));}
6、测试代码
#include <iostream>#include "Pinger.h"using namespace std;int main(){ cout << "Hello World!" << endl; for(int i=0;i<10;i++){ Pinger p; p.ping("192.168.1.1",1,200,200); cout<<p.getTips().c_str()<<endl; } return 0;}
7、输出
ping了10包,有一包未回。
Hello World!wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:15 ms, seq:0, id:0.close sock:132,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:16 ms, seq:0, id:1.close sock:120,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:0 ms, seq:0, id:2.close sock:116,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:0 ms, seq:0, id:3.close sock:112,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:0 ms, seq:0, id:4.close sock:124,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:16 ms, seq:0, id:5.close sock:132,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:15 ms, seq:0, id:6.close sock:120,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:15 ms, seq:0, id:7.close sock:116,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:-1,rcvErrCode:10060.close sock:112,ret:0,errCode:0wsa init ret 0,errCode:0.ping tips.set send time-out 200,ret:0,errCode:0.set recv time-out 200,ret:0,errCode:0.send,ret:43,sndErrCode:0,recv,ret:63,rcvErrCode:0.reply from 192.168.1.1, 43 bytes, time:15 ms, seq:0, id:9.close sock:124,ret:0,errCode:0
wireshark抓包截图如下:
从抓包看id设置时候高低字节没有倒一下。。。
8、git链接
此工程的git链接。
https://github.com/junbujianwpl/Pinger.git
9、编译器warning
谁能告诉偶彼样修改代码消除此2类warning。别说禁止第几号提示之类的。。。。。。
warning1:
p.ping("192.168.1.1",2,200,200);
main.cpp:11: warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings] p.ping("192.168.1.1",2,200,200); ^
warning2:
sprintf(tips,"reply from %s, %u bytes, time:%u ms, seq:%d.\n",inet_ntoa(from->sin_addr), bread-wIpHeadLen,GetTickCount()-icmpHead->ulTimeStamp,icmpHead->usSeq);
Pinger.cpp:136: warning: format '%u' expects argument of type 'unsigned int', but argument 5 has type 'DWORD {aka long unsigned int}' [-Wformat=] bread-wIpHeadLen,GetTickCount()-icmpHead->ulTimeStamp,icmpHead->usSeq); ^
10、git创建仓库命令
cd pro_pathgit initgit add *git commit -m "first version"git remote add origin your_git_urigit fetch your_git_urigit pull your_git_uri --allow-unrelated-historiesgit push -u origin master
11、错误码
create sock failed,errcode:10013
需要管理员权限,在win7下,以管理员权限运行Qt。
12、部分错误码表
来自msdn。
阅读全文
0 0
- Windows下基于Qt用c++实现ping
- windows下用C语言实现ping
- C实现Windows下的ping功能
- windows下ping实现
- Windows下使用C语言实现Ping的源码
- Windows下C语言实现计算机网络底层Ping功能
- windows下ping程序实现
- Windows下PING程序实现
- windows下ping程序实现
- 基于C语言实现的Ping程序
- 基于C语言实现的Ping程序
- Linux下用C语言实现Ping程序功能
- Linux下用C语言实现Ping程序功能
- Linux下用C语言实现Ping程序功能
- Linux下用c实现通过ping检测连接
- linux下ping的C语言实现
- linux下ping的C语言实现
- 用C 语言实现 Ping
- TPshop学习(8)微信支付
- js JSON
- 八大排序算法总结与java实现
- 【WEB】Vue2.0音乐APP实战中的知识点总结(四)
- 寻找最大数(二)
- Windows下基于Qt用c++实现ping
- 《马云给年轻人的77条忠告》读书笔记
- final关键字的使用
- 停止java线程的方法及详解
- 如何避免梯度爆炸梯度消失
- cocos2dx基础——坐标系
- A
- 直接插入排序
- SSM:Spring,SpringMVC与MyBatis整合