vc++Ping下令模拟
vc++Ping命令模拟
今天思考如何用程序实现IP的探测,网上查了一些资料,要了解ICMP协议
ICMP是ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议。ICMP协议主要用来控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息
参考了《Visual c++网络程序设计实例详解》的代码后,在作者的基础上稍微修改了下以便在VC2005正常运行
下面是例子代码
今天思考如何用程序实现IP的探测,网上查了一些资料,要了解ICMP协议
ICMP是ICMP是(Internet Control Message Protocol)Internet控制报文协议。它是TCP/IP协议族的一个子协议。ICMP协议主要用来控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息
参考了《Visual c++网络程序设计实例详解》的代码后,在作者的基础上稍微修改了下以便在VC2005正常运行
下面是例子代码
// 目的IP地址,即要Ping的IP地址 char szDestIp[] = "169.254.41.36"; // 127.0.0.1 // 创建原始套节字 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); // 设置接收超时 SetTimeout(sRaw, 3000, TRUE); // 设置目的地址 SOCKADDR_IN dest; dest.sin_family = AF_INET; dest.sin_port = htons(0); dest.sin_addr.S_un.S_addr = inet_addr(szDestIp); // 创建ICMP封包 char buff[sizeof(ICMP_HDR) + 32]; ICMP_HDR* pIcmp = (ICMP_HDR*)buff; // 填写ICMP封包数据,请求一个ICMP回显 pIcmp->icmp_type = 8; pIcmp->icmp_code = 0; pIcmp->icmp_id = (USHORT)GetCurrentProcessId(); pIcmp->icmp_checksum = 0; pIcmp->icmp_sequence = 0; // 填充数据部分,可以为任意 memset(&buff[sizeof(ICMP_HDR)], 'E', 32); // 开始发送和接收ICMP封包 USHORT nSeq = 0; char recvBuf[1024]; SOCKADDR_IN from; int nLen = sizeof(from); while(TRUE) { static int nCount = 0; int nRet; // ping次数 if(nCount++ == 1000) break; pIcmp->icmp_checksum = 0; pIcmp->icmp_timestamp = GetTickCount(); pIcmp->icmp_sequence = nSeq++; pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) + 32); nRet = sendto(sRaw, buff, sizeof(ICMP_HDR) + 32, 0, (SOCKADDR *)&dest, sizeof(dest)); if(nRet == SOCKET_ERROR) { printf(" sendto() failed: %d \n", ::WSAGetLastError()); return -1; } nRet = recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen); if(nRet == SOCKET_ERROR) { if(WSAGetLastError() == WSAETIMEDOUT) { printf(" timed out\n"); continue; } printf("recvfrom() failed: %d\n", WSAGetLastError()); return -1; } // 下面开始解析接收到的ICMP封包 int nTick = ::GetTickCount(); if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR)) { printf(" Too few bytes from %s \n", inet_ntoa(from.sin_addr)); } // 接收到的数据中包含IP头,IP头大小为20个字节,所以加20得到ICMP头 // (ICMP_HDR*)(recvBuf + sizeof(IPHeader)); ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + 20); if(pRecvIcmp->icmp_type != 0) // 回显 { printf(" nonecho type %d recvd \n", pRecvIcmp->icmp_type); return -1; } if(pRecvIcmp->icmp_id != GetCurrentProcessId()) { printf(" someone else's packet! \n"); return -1; } printf("从 %s 返回 %d 字节:", inet_ntoa(from.sin_addr),nRet); printf(" 数据包序列号 = %d. \t", pRecvIcmp->icmp_sequence); printf(" 延时大小: %d ms", nTick - pRecvIcmp->icmp_timestamp); printf(" \n"); // 每一秒发送一次就行了 Sleep(1000); } WSACleanup(); closesocket(sRaw);