基于icmp的ping函数

基于icmp的ping端口小程序,与系统自带的ping对比之后 准确率很高

由于是想快速扫描 而非准确扫描 所以很多错误细节没有考虑在内

循环次数还是等待时间都比较低 根据需要可以进行修改

 

cpp文件

 

// // Construction/Destruction // //创建网络环境 以及新建一个socket SOCKET SocketInit() { // 初始化WinSock库 WORD wVersionRequested = MAKEWORD(2,2); WSADATA wsaData; if ( WSAStartup( wVersionRequested, &wsaData ) != 0 ) return FALSE ; // 创建原始套接字 return socket ( AF_INET, SOCK_RAW, IPPROTO_ICMP ) ; } //关闭socket以及关闭网络环境 void SocketClose(SOCKET socket) { if (socket != INVALID_SOCKET) { closesocket (socket) ; } WSACleanup () ; } // 实现PING程序 // 参数:目标地址IP字符串,格式如"127.0.0.1" // 判断目标主机是否存活 BOOL IcmpPingSource(char* lpDestIp,SOCKET RawSock) { // 设置目标地址 SOCKADDR_IN DestSockAddr = {0}; DestSockAddr.sin_family = AF_INET ; DestSockAddr.sin_addr.s_addr = inet_addr( lpDestIp ) ; DestSockAddr.sin_port = htons(0) ; // 创建ICMP回显请求包(PACK_HAEAD + PACK_DATA) char ICMPPack[ICMP_PACK_SIZE] = {0}; PICMP_HEADER pICMPHeader = (PICMP_HEADER)ICMPPack ; pICMPHeader->bType = ICMP_PING_QUERY_TYPE; pICMPHeader->bCode = 0 ; pICMPHeader->nCheckSum = 0; pICMPHeader->nTimeStamp = 0; memset ( &(ICMPPack[ICMP_HEADER_SIZE]), 'E', ICMP_DATA_SIZE ) ; // 填充数据部分,内容任意 // 设置接收超时为1秒 在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限 int nTime = 100; int nret = setsockopt ( RawSock, SOL_SOCKET,SO_SNDTIMEO, (char*)&nTime, sizeof(nTime)); if (nret == SOCKET_ERROR) { return FALSE; } nret = setsockopt ( RawSock, SOL_SOCKET,SO_RCVTIMEO, (char*)&nTime, sizeof(nTime)); if (nret == SOCKET_ERROR) { return FALSE; } char szRecvBuf [ DEF_BUF_SIZE] ; SOCKADDR_IN SourSockAddr = {0}; //快速扫描 只循环4/2次吧 for ( int i = 0 ; i < 2; i++ ) { pICMPHeader->nCheckSum = 0; // 初始时校验值为0 pICMPHeader->nSequence = i; // 序号 pICMPHeader->nTimeStamp = GetTickCount() ; // 当前时间 // 计算校验值,校验值要在ICMP数据报创建完才能计算 pICMPHeader->nCheckSum = GetCheckSum ( (LPBYTE)ICMPPack, ICMP_PACK_SIZE ) ; // 发送ICMP数据包 int nRet = ::sendto (RawSock, ICMPPack, ICMP_PACK_SIZE,0,(SOCKADDR*)&DestSockAddr, sizeof(DestSockAddr)); if ( nRet == SOCKET_ERROR ) { return FALSE ; } // 接收ICMP响应 int nLen = sizeof(SourSockAddr); nRet = recvfrom ( RawSock, szRecvBuf, DEF_BUF_SIZE,0,(SOCKADDR*)&SourSockAddr, &nLen); if (nRet == SOCKET_ERROR) { if ( (WSAETIMEDOUT == WSAGetLastError()) && (i < (2-1))) { ::Sleep(100); continue; //如果超时再给一次几乎 } return FALSE; } if (SourSockAddr.sin_addr.s_addr == inet_addr(lpDestIp)) { //发出去的ip与回显的ip相同才是通的 return TRUE; } } return FALSE; } // 计算ICMP包校验值 // 参数1:ICMP包缓冲区 // 参数2:ICMP包长度 USHORT GetCheckSum ( LPBYTE lpBuf, DWORD dwSize ) { DWORD dwCheckSum = 0 ; USHORT* lpWord = (USHORT*)lpBuf ; // 累加 while ( dwSize > 1 ) { dwCheckSum += *lpWord++ ; dwSize -= 2 ; } // 如果长度是奇数 if ( dwSize == 1 ) dwCheckSum += *((LPBYTE)lpWord) ; // 高16位和低16位相加 dwCheckSum = ( dwCheckSum >> 16 ) + ( dwCheckSum & 0xFFFF ) ; // 取反 return (USHORT)(~dwCheckSum ) ; }

 

.h文件

#include "Winsock2.h" #pragma comment ( lib, "ws2_32.lib" ) #include #include "stdio.h" // 定义默认的缓冲区长度 #define DEF_BUF_SIZE 1024 // 定义IP包头长度 #define IP_HEADER_SIZE 20 // 定义ICMP包头长度 #define ICMP_HEADER_SIZE ( sizeof(ICMP_HEADER) ) // 定义ICMP包实体数据长度 #define ICMP_DATA_SIZE 32 // 定义ICMP包总长度 #define ICMP_PACK_SIZE ( ICMP_HEADER_SIZE + ICMP_DATA_SIZE ) //定义ping数据包类型 (查询) #define ICMP_PING_QUERY_TYPE 8 // 定义ICMP包头 typedef struct _ICMP_HEADER { BYTE bType ; // 类型 BYTE bCode ; // 代码 USHORT nCheckSum ; // 校验和 USHORT nSequence ; // 序列号 UINT nTimeStamp ; // 可选项,这里为时间,用于计算时间 } ICMP_HEADER, *PICMP_HEADER ; // 用于格式化输出信息的缓冲区 BOOL IcmpPingSource(char* lpDestIp,SOCKET RawSock); USHORT GetCheckSum ( LPBYTE lpBuf, DWORD dwSize ); SOCKET SocketInit(); void SocketClose(SOCKET socket);

你可能感兴趣的:(网络编程)