【网络编程】之十三、ping程序实现
使用原始套接字:SOCK_RAW
需要ICMP
代码如下:
#include<iostream> #include<WinSock2.h> using namespace std; #pragma comment(lib, "WS2_32.lib") typedef struct icmp_hdr{ unsigned char icmp_type; unsigned char icmp_code; unsigned short icmp_checksum; unsigned short icmp_id; unsigned short icmp_sequence; unsigned long icmp_timnestamp; }ICMP_HDR, *PICMP_HDR; typedef struct _IPHeader{ UCHAR iphVerLen; UCHAR ipTOS; USHORT ipLength; USHORT ipID; USHORT ipFlags; UCHAR ipTTL; UCHAR ipProtocol; USHORT ipChecksum; ULONG ipSource; ULONG ipDestination; }IPHeader, *PIPHeader; USHORT checksum(USHORT* buffer, int size) { unsigned long cksum = 0; while(size > 1) { cksum += *buffer++; size -= sizeof(USHORT); } // 奇数,将最后一个字节扩展到双字, 再累加 if(size) cksum += *(UCHAR*)buffer; //高16 低16相加,取反 cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (USHORT)(~cksum); } int main(void) { char szDestIp[] = "127.0.0.1"; SOCKET sRaw= ::socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //SetTimeout(sRaw, 1000, TRUE); SOCKADDR_IN dest; dest.sin_family = AF_INET; dest.sin_port = htons(5674); dest.sin_addr.S_un.S_addr = inet_addr(szDestIp); char buff[sizeof(ICMP_HDR) + 32]; ICMP_HDR *pIcmp = (ICMP_HDR*)buff; pIcmp->icmp_type = 8; pIcmp->icmp_code = 0; pIcmp->icmp_id = (USHORT)::GetCurrentProcess(); pIcmp->icmp_checksum = 0; pIcmp->icmp_sequence = 0; memset(&buff[sizeof(ICMP_HDR)], 'E', 32); //发送 USHORT nSeq = 0; char recvBuf[1024]; SOCKADDR_IN from; int nLen = sizeof(from); while(TRUE) { static int nCount = 0; int nRet; if(nCount++ == 4) break; pIcmp->icmp_checksum = 0; pIcmp->icmp_timnestamp = ::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) { cout << "sendto error:" << ::WSAGetLastError() << endl; return -1; } nRet = ::recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen); if(nRet == SOCKET_ERROR) { if(::WSAGetLastError() == WSAETIMEDOUT) { cout << "time out" << endl; continue; } cout << "recvfrom failed:" << ::WSAGetLastError() << endl; return -1; } //解析 int nTick = ::GetTickCount(); if(nRet < sizeof(IPHeader) + sizeof(ICMP_HDR)) { cout << "Too few bytes from " << ::inet_ntoa(from.sin_addr) << endl; } ICMP_HDR *pRecvIcmp = (ICMP_HDR*)(recvBuf + sizeof(IPHeader)); if(pRecvIcmp->icmp_type != 0) { cout << "nonecho type " << pRecvIcmp->icmp_type << " recvd" << endl; return -1; } if(pRecvIcmp->icmp_id != ::GetCurrentProcessId()) { cout << "someone ele's packet!" << endl; return -1; } cout << nRet << " bytes from " << inet_ntoa(from.sin_addr) ; cout << "icmp_seq = " << pRecvIcmp->icmp_sequence ; cout << "time: " << nTick - pRecvIcmp->icmp_timnestamp << " ms"; cout << endl; Sleep(1000); } return 0; }
jofranks 13.7.24 于南昌