stoneage8.5/石器时代8.5客户端最新源代码/石器源码/wgs/Ping.cpp
2020-06-22 17:49:02 +08:00

219 lines
3.9 KiB
C++

//ping.cpp
#include <Winsock2.h>
#include <Windows.h>
#include "ping.h"
#pragma comment(lib, "ws2_32.lib")
bool CPing::Ping(LPCSTR pstrHost, UINT nRetries)
{
//创建一个Raw套节字
SOCKET rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == INVALID_SOCKET)
{
int err = WSAGetLastError();
return false;
}
int nNetTimeout = 1000;//1秒
//发送时限
setsockopt(rawSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&nNetTimeout, sizeof(int));
//接收时限
setsockopt(rawSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
//获得主机信息
LPHOSTENT lpHost = gethostbyname(pstrHost);
if (lpHost == NULL)
{
return false;
}
//构造目标套节字地址信息
struct sockaddr_in saDest;
struct sockaddr_in saSrc;
saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
saDest.sin_family = AF_INET;
saDest.sin_port = 3077;
DWORD dwTimeSent;
u_char cTTL;
int nRet;
int nRecvNum = 0;
int nTotalTime = 0;
//多次ping
for (UINT nLoop = 0; nLoop < nRetries; ++nLoop)
{
//发送ICMP回应请求
if ((nRet = SendEchoRequest(rawSocket, &saDest)) < 0)
{
break;
}
if ((nRet = WaitForEchoReply(rawSocket)) == SOCKET_ERROR)
{
break;
}
if (nRet)
{
//获得回应
if ((dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL)) < 0)
{
nRet = dwTimeSent;
break;
}
//计算时间
nTotalTime += GetTickCount() - dwTimeSent;
++nRecvNum;
}
}
closesocket(rawSocket);
if (nRecvNum > 0 && nRet >= 0)
{
m_Result.nElapseTime = nTotalTime / nRetries;
m_Result.cTTL = cTTL;
m_Result.fMissPack = (float)(nRetries - nRecvNum) / nRetries;
return true;
}
return false;
}
//发送ICMPECHO数据包请求
int CPing::SendEchoRequest(SOCKET s, LPSOCKADDR_IN lpstToAddr)
{
static ECHOREQUEST echoReq;
static int nId = 1;
static int nSeq = 1;
int nRet;
//构造回应请求
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
echoReq.cData[nRet] = ' ' + nRet;
//保存发送时间
echoReq.dwTime = GetTickCount();
echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
//发送请求
nRet = sendto(s,
(LPSTR)&echoReq,
sizeof(ECHOREQUEST),
0,
(LPSOCKADDR)lpstToAddr,
sizeof(SOCKADDR_IN));
//检查返回值
if (nRet == SOCKET_ERROR)
{
}
return (nRet);
}
//接收ICMPECHO数据包回应
DWORD CPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
//接收请求回应
nRet = recvfrom(s,
(LPSTR)&echoReply,
sizeof(ECHOREPLY),
0,
(LPSOCKADDR)lpsaFrom,
&nAddrLen);
//检查返回值
if (nRet == SOCKET_ERROR)
{
return nRet;
}
//返回发送的时间
*pTTL = echoReply.ipHdr.TTL;
return(echoReply.echoRequest.dwTime);
}
//等待回应
int CPing::WaitForEchoReply(SOCKET s)
{
struct timeval Timeout;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(s,&readfds);
Timeout.tv_sec = 1;
Timeout.tv_usec = 0;
int ret = select(s+1, &readfds, NULL, NULL, &Timeout);
return ret;
}
//转换地址
u_short CPing::in_cksum(u_short *addr, int len)
{
register int nleft = len;
register u_short *w = addr;
register u_short answer;
register int sum = 0;
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
u_short u = 0;
*(u_char *)(&u) = *(u_char *)w;
sum += u;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
void CPing::Result(int* nElapseTime, float* fMissPack, u_char* cTTL)
{
if (nElapseTime)
{
*nElapseTime = m_Result.nElapseTime;
}
if (fMissPack)
{
*fMissPack = m_Result.fMissPack;
}
if (cTTL)
{
*cTTL = m_Result.cTTL;
}
}