此份ping的源码来自于vc6对应msdn中。自己稍做修改,然后成了现在这个版本。
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是为了保证原有代码可用的一个措施。。。。。。。。
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += main.cpp \
Pinger.cpp
HEADERS += \
Pinger.h
#Qt下导入winsock。2个版本的都在这里面了。
LIBS += -lWS2_32
#ifndef PINGER_H
#define PINGER_H
#include
#include
#include
#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; ///
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; ///
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 8
class 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
#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));
}
#include
#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<return 0;
}
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:0
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:16 ms, seq:0, id:1.
close sock:120,ret:0,errCode:0
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:0 ms, seq:0, id:2.
close sock:116,ret:0,errCode:0
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:0 ms, seq:0, id:3.
close sock:112,ret:0,errCode:0
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:0 ms, seq:0, id:4.
close sock:124,ret:0,errCode:0
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:16 ms, seq:0, id:5.
close sock:132,ret:0,errCode:0
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:6.
close sock:120,ret:0,errCode:0
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:7.
close sock:116,ret:0,errCode:0
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:-1,rcvErrCode:10060.
close sock:112,ret:0,errCode:0
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:9.
close sock:124,ret:0,errCode:0
从抓包看id设置时候高低字节没有倒一下。。。
此工程的git链接。
https://github.com/junbujianwpl/Pinger.git
谁能告诉偶彼样修改代码消除此2类warning。别说禁止第几号提示之类的。。。。。。
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);
^
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);
^
cd pro_path
git init
git add *
git commit -m "first version"
git remote add origin your_git_uri
git fetch your_git_uri
git pull your_git_uri --allow-unrelated-histories
git push -u origin master
create sock failed,errcode:10013
需要管理员权限,在win7下,以管理员权限运行Qt。
来自msdn。
code | descprition |
---|---|
WSAEBADF 10009 | File handle is not valid.The file handle supplied is not valid. |
WSAEACCES 10013 | Permission denied.An attempt was made to access a socket in a way forbidden by its access permissions. An example is using a broadcast address for sendto without broadcast permission being set using setsockopt(SO_BROADCAST).Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4.0 with SP4 and later), another application, service, or kernel mode driver is bound to the same address with exclusive access. Such exclusive access is a new feature of Windows NT 4.0 with SP4 and later, and is implemented by using the SO_EXCLUSIVEADDRUSE option. |
WSAEFAULT 10014 | Bad address.The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr). |
WSAEINVAL 10022 | Invalid argument.Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening. |
WSAEMFILE 10024 | Too many open files.Too many open sockets. Each implementation may have a maximum number of socket handles available, either globally, per process, or per thread. |
WSAEWOULDBLOCK 10035 | Resource temporarily unavailable.This error is returned from operations on nonblocking sockets that cannot be completed immediately, for example recv when no data is queued to be read from the socket. It is a nonfatal error, and the operation should be retried later. It is normal for WSAEWOULDBLOCK to be reported as the result from calling connect on a nonblocking SOCK_STREAM socket, since some time must elapse for the connection to be established. |
WSAEINPROGRESS 10036 | Operation now in progress.A blocking operation is currently executing. Windows Sockets only allows a single blocking operation—per- task or thread—to be outstanding, and if any other function call is made (whether or not it references that or any other socket) the function fails with the WSAEINPROGRESS error. |