//ping.cpp #include #include #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; } }