C++实现ping功能的代码
2018-07-20 来源:open-open
/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS ping utility * FILE: base/applications/network/ping/ping.c * PURPOSE: Network test utility * PROGRAMMERS: */ #include <winsock2.h> #include <ws2tcpip.h> #include <tchar.h> #include <stdarg.h> #include <string.h> #include <stdio.h> #pragma comment( lib, "ws2_32.lib" ) #define ULONG_MAX 0xffffffffUL /* General ICMP constants */ #define ICMP_MINSIZE 8 /* Minimum ICMP packet size */ #define ICMP_MAXSIZE 65535 /* Maximum ICMP packet size */ /* ICMP message types */ #define ICMPMSG_ECHOREQUEST 8 /* ICMP ECHO request message */ #define ICMPMSG_ECHOREPLY 0 /* ICMP ECHO reply message */ #pragma pack(4) /* IPv4 header structure */ typedef struct _IPv4_HEADER { unsigned char IHL:4; unsigned char Version:4; unsigned char TOS; unsigned short Length; unsigned short Id; unsigned short FragFlags; unsigned char TTL; unsigned char Protocol; unsigned short Checksum; unsigned int SrcAddress; unsigned int DstAddress; } IPv4_HEADER, *PIPv4_HEADER; /* ICMP echo request/reply header structure */ typedef struct _ICMP_HEADER { unsigned char Type; unsigned char Code; unsigned short Checksum; unsigned short Id; unsigned short SeqNum; } ICMP_HEADER, *PICMP_HEADER; typedef struct _ICMP_ECHO_PACKET { ICMP_HEADER Icmp; } ICMP_ECHO_PACKET, *PICMP_ECHO_PACKET; #pragma pack(1) BOOL NeverStop; BOOL ResolveAddresses; UINT PingCount; UINT DataSize; /* ICMP echo request data size */ BOOL DontFragment; ULONG TTLValue; ULONG TOSValue; ULONG Timeout; WCHAR TargetName[256]; SOCKET IcmpSock; SOCKADDR_IN Target; WCHAR TargetIP[16]; FD_SET Fds; TIMEVAL Timeval; UINT CurrentSeqNum; UINT SentCount; UINT LostCount; BOOL MinRTTSet; LARGE_INTEGER MinRTT; /* Minimum round trip time in microseconds */ LARGE_INTEGER MaxRTT; LARGE_INTEGER SumRTT; LARGE_INTEGER AvgRTT; LARGE_INTEGER TicksPerMs; /* Ticks per millisecond */ LARGE_INTEGER TicksPerUs; /* Ticks per microsecond */ LARGE_INTEGER SentTime; BOOL UsePerformanceCounter; HANDLE hStdOutput; #ifndef NDEBUG /* Display the contents of a buffer */ static VOID DisplayBuffer( PVOID Buffer, DWORD Size) { UINT i; PCHAR p; printf("Buffer (0x%p) Size (0x%lX).\n", Buffer, Size); p = (PCHAR)Buffer; for (i = 0; i < Size; i++) { if (i % 16 == 0) printf("\n"); printf("%02X ", (p[i]) & 0xFF); } } #endif /* !NDEBUG */ /* Display usage information on screen */ static VOID Usage(VOID) { printf("用法:ping [-t] [-n 次数] [-l 大小] [-w 超时] 目标主机\n\n\ 选项:\n\ -t 不停呼叫指定的主机直到被终止。\n\ 要停止 - 按下 Ctrl-C。\n\ -n 次数 发送回响包的次数。\n\ -l 大小 发送包的大小。\n\ -w 超时 等待每个回复的时间(毫秒)。\n\n\0"); } /* Reset configuration to default values */ static VOID Reset(VOID) { LARGE_INTEGER PerformanceCounterFrequency; NeverStop = FALSE; ResolveAddresses = FALSE; PingCount = 4; DataSize = 32; DontFragment = FALSE; TTLValue = 128; TOSValue = 0; Timeout = 1000; UsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency); if (UsePerformanceCounter) { /* Performance counters may return incorrect results on some multiprocessor platforms so we restrict execution on the first processor. This may fail on Windows NT so we fall back to GetCurrentTick() for timing */ if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0) UsePerformanceCounter = FALSE; /* Convert frequency to ticks per millisecond */ TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000; /* And to ticks per microsecond */ TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000; } if (!UsePerformanceCounter) { /* 1 tick per millisecond for GetCurrentTick() */ TicksPerMs.QuadPart = 1; /* GetCurrentTick() cannot handle microseconds */ TicksPerUs.QuadPart = 1; } } /* * Convert a unicode string to an unsigned long integer. * * Ignores `locale' stuff. Assumes that the upper and lower case * alphabets and digits are each contiguous. * * @implemented */ unsigned long wcstoul(const wchar_t *nptr, wchar_t **endptr, int base) { const wchar_t *s = nptr; unsigned long acc; int c; unsigned long cutoff; int neg = 0, any, cutlim; /* * See strtol for comments as to the logic used. */ do { c = *s++; } while (iswctype(c, _SPACE)); if (c == L'-') { neg = 1; c = *s++; } else if (c == L'+') c = *s++; if ((base == 0 || base == 16) && c == L'0' && (*s == L'x' || *s == L'X')) { c = s[1]; s += 2; base = 16; } if (base == 0) base = c == L'0' ? 8 : 10; cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; for (acc = 0, any = 0;; c = *s++) { if (iswctype(c, _DIGIT)) c -= L'0'; else if (iswctype(c, _ALPHA)) c -= iswctype(c, _UPPER) ? L'A' - 10 : L'a' - 10; else break; if (c >= base) break; if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) any = -1; else { any = 1; acc *= base; acc += c; } } if (any < 0) { acc = ULONG_MAX; } else if (neg) acc = 0-acc; if (endptr != 0) *endptr = any ? (wchar_t *)((size_t)(s - 1)) : (wchar_t *)((size_t)nptr); return acc; } /* Parse command line parameters */ static BOOL ParseCmdline(int argc, LPWSTR argv[]) { INT i; BOOL FoundTarget = FALSE, InvalidOption = FALSE; if (argc < 2) { Usage(); return FALSE; } for (i = 1; i < argc; i++) { if (argv[i][0] == L'-' || argv[i][0] == L'/') { switch (argv[i][1]) { case L't': NeverStop = TRUE; break; case L'a': ResolveAddresses = TRUE; break; case L'n': if (i + 1 < argc) PingCount = wcstoul(argv[++i], NULL, 0); else InvalidOption = TRUE; break; case L'l': if (i + 1 < argc) { DataSize = wcstoul(argv[++i], NULL, 0); if (DataSize > ICMP_MAXSIZE - sizeof(ICMP_ECHO_PACKET) - sizeof(IPv4_HEADER)) { printf("-l 选项的值无效,有效的范围是从 0 到 %1!d!。\n\0",ICMP_MAXSIZE - \ (int)sizeof(ICMP_ECHO_PACKET) - \ (int)sizeof(IPv4_HEADER)); return FALSE; } } else InvalidOption = TRUE; break; case L'f': DontFragment = TRUE; break; case L'i': if (i + 1 < argc) TTLValue = wcstoul(argv[++i], NULL, 0); else InvalidOption = TRUE; break; case L'v': if (i + 1 < argc) TOSValue = wcstoul(argv[++i], NULL, 0); else InvalidOption = TRUE; break; case L'w': if (i + 1 < argc) Timeout = wcstoul(argv[++i], NULL, 0); else InvalidOption = TRUE; break; case '?': Usage(); return FALSE; default: printf("错误选项 %1。\n\0", argv[i]); return FALSE; } if (InvalidOption) { printf("错误选项格式 %1。\n\0", argv[i]); return FALSE; } } else { if (FoundTarget) { printf("错误参数 %1。\n\0", argv[i]); return FALSE; } else { wcscpy(TargetName, argv[i]); FoundTarget = TRUE; } } } if (!FoundTarget) { printf("目标主机的名称或 IP 地址必须被指定。\n\0"); return FALSE; } return TRUE; } /* Calculate checksum of data */ static WORD Checksum(PUSHORT data, UINT size) { ULONG sum = 0; while (size > 1) { sum += *data++; size -= sizeof(USHORT); } if (size) sum += *(UCHAR*)data; sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16); return (USHORT)(~sum); } /* Prepare to ping target */ static BOOL Setup(VOID) { WORD wVersionRequested; WSADATA WsaData; INT Status; ULONG Addr; PHOSTENT phe; CHAR aTargetName[256]; wVersionRequested = MAKEWORD(2, 2); Status = WSAStartup(wVersionRequested, &WsaData); if (Status != 0) { printf("不能初始化 winsock dll。\n\0"); return FALSE; } IcmpSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0); if (IcmpSock == INVALID_SOCKET) { printf("不能创建套接字 (#%1!d!)。\n\0", WSAGetLastError()); return FALSE; } if (setsockopt(IcmpSock, IPPROTO_IP, IP_DONTFRAGMENT, (const char *)&DontFragment, sizeof(DontFragment)) == SOCKET_ERROR) { printf("setsockopt 失败 (%1!d!)。\n\0", WSAGetLastError()); return FALSE; } if (setsockopt(IcmpSock, IPPROTO_IP, IP_TTL, (const char *)&TTLValue, sizeof(TTLValue)) == SOCKET_ERROR) { printf("setsockopt 失败 (%1!d!)。\n\0", WSAGetLastError()); return FALSE; } if(!WideCharToMultiByte(CP_ACP, 0, TargetName, -1, aTargetName,\ sizeof(aTargetName), NULL, NULL)) { printf("未知主机 %1。\n\0", TargetName); return FALSE; } ZeroMemory(&Target, sizeof(Target)); phe = NULL; Addr = inet_addr(aTargetName); if (Addr == INADDR_NONE) { phe = gethostbyname(aTargetName); if (phe == NULL) { printf("未知主机 %1。\n\0", TargetName); return FALSE; } CopyMemory(&Target.sin_addr, phe->h_addr, phe->h_length); Target.sin_family = phe->h_addrtype; } else { Target.sin_addr.s_addr = Addr; Target.sin_family = AF_INET; } swprintf(TargetIP, L"%d.%d.%d.%d", Target.sin_addr.S_un.S_un_b.s_b1,\ Target.sin_addr.S_un.S_un_b.s_b2,\ Target.sin_addr.S_un.S_un_b.s_b3,\ Target.sin_addr.S_un.S_un_b.s_b4); CurrentSeqNum = 1; SentCount = 0; LostCount = 0; MinRTT.QuadPart = 0; MaxRTT.QuadPart = 0; SumRTT.QuadPart = 0; MinRTTSet = FALSE; return TRUE; } /* Close socket */ static VOID Cleanup(VOID) { if (IcmpSock != INVALID_SOCKET) closesocket(IcmpSock); WSACleanup(); } static VOID QueryTime(PLARGE_INTEGER Time) { if (UsePerformanceCounter) { if (QueryPerformanceCounter(Time) == 0) { /* This should not happen, but we fall back to GetCurrentTick() if it does */ Time->u.LowPart = (ULONG)GetTickCount(); Time->u.HighPart = 0; /* 1 tick per millisecond for GetCurrentTick() */ TicksPerMs.QuadPart = 1; /* GetCurrentTick() cannot handle microseconds */ TicksPerUs.QuadPart = 1; UsePerformanceCounter = FALSE; } } else { Time->u.LowPart = (ULONG)GetTickCount(); Time->u.HighPart = 0; } } /* * @implemented */ wchar_t * _i64tow(__int64 value, wchar_t *string, int radix) { ULONGLONG val; int negative; WCHAR buffer[65]; PWCHAR pos; WCHAR digit; if (value < 0 && radix == 10) { negative = 1; val = -value; } else { negative = 0; val = value; } /* if */ pos = &buffer[64]; *pos = '\0'; do { digit = (WCHAR)(val % radix); val = val / radix; if (digit < 10) { *--pos = '0' + digit; } else { *--pos = 'a' + digit - 10; } /* if */ } while (val != 0L); if (negative) { *--pos = '-'; } /* if */ if (string != NULL) { memcpy(string, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR)); } /* if */ return string; } static VOID TimeToMsString(LPWSTR String, LARGE_INTEGER Time) { WCHAR Convstr[40]; LARGE_INTEGER LargeTime; LargeTime.QuadPart = Time.QuadPart / TicksPerMs.QuadPart; _i64tow(LargeTime.QuadPart, Convstr, 10); wcscpy(String, Convstr); wcscat(String, L"ms\0"); } /* Locate the ICMP data and print it. Returns TRUE if the packet was good, FALSE if not */ static BOOL DecodeResponse(PCHAR buffer, UINT size, PSOCKADDR_IN from) { PIPv4_HEADER IpHeader; PICMP_ECHO_PACKET Icmp; UINT IphLength; WCHAR Time[100]; LARGE_INTEGER RelativeTime; LARGE_INTEGER LargeTime; WCHAR Sign[2]; WCHAR wfromIP[16]; IpHeader = (PIPv4_HEADER)buffer; IphLength = IpHeader->IHL * 4; if (size < IphLength + ICMP_MINSIZE) { #ifndef NDEBUG printf("Bad size (0x%X < 0x%X)\n", size, IphLength + ICMP_MINSIZE); #endif /* !NDEBUG */ return FALSE; } Icmp = (PICMP_ECHO_PACKET)(buffer + IphLength); if (Icmp->Icmp.Type != ICMPMSG_ECHOREPLY) { #ifndef NDEBUG printf("Bad ICMP type (0x%X should be 0x%X)\n", Icmp->Icmp.Type, ICMPMSG_ECHOREPLY); #endif /* !NDEBUG */ return FALSE; } if (Icmp->Icmp.Id != (USHORT)GetCurrentProcessId()) { #ifndef NDEBUG printf("Bad ICMP id (0x%X should be 0x%X)\n", Icmp->Icmp.Id, (USHORT)GetCurrentProcessId()); #endif /* !NDEBUG */ return FALSE; } if (from->sin_addr.s_addr != Target.sin_addr.s_addr) { #ifndef NDEBUG printf("Bad source address (%s should be %s)\n", inet_ntoa(from->sin_addr), inet_ntoa(Target.sin_addr)); #endif /* !NDEBUG */ return FALSE; } QueryTime(&LargeTime); RelativeTime.QuadPart = (LargeTime.QuadPart - SentTime.QuadPart); if ((RelativeTime.QuadPart / TicksPerMs.QuadPart) < 1) { wcscpy(Sign, L"<"); wcscpy(Time, L"1ms\0"); } else { wcscpy(Sign, L"="); TimeToMsString(Time, RelativeTime); } swprintf(wfromIP, L"%d.%d.%d.%d", from->sin_addr.S_un.S_un_b.s_b1,\ from->sin_addr.S_un.S_un_b.s_b2,\ from->sin_addr.S_un.S_un_b.s_b3,\ from->sin_addr.S_un.S_un_b.s_b4); printf("来自 %1 的回复:字节数=%2!d! 时间%3%4 TTL=%5!d!\n\0", wfromIP,\ size - IphLength - (int)sizeof(ICMP_ECHO_PACKET),\ Sign, Time, IpHeader->TTL); if (RelativeTime.QuadPart < MinRTT.QuadPart || !MinRTTSet) { MinRTT.QuadPart = RelativeTime.QuadPart; MinRTTSet = TRUE; } if (RelativeTime.QuadPart > MaxRTT.QuadPart) MaxRTT.QuadPart = RelativeTime.QuadPart; SumRTT.QuadPart += RelativeTime.QuadPart; return TRUE; } /* Send and receive one ping */ static BOOL Ping(VOID) { INT Status; SOCKADDR From; INT Length; PVOID Buffer; UINT Size; PICMP_ECHO_PACKET Packet; /* Account for extra space for IP header when packet is received */ Size = DataSize + 128; Buffer = GlobalAlloc(0, Size); if (!Buffer) { printf("空闲资源不足。\n\0"); return FALSE; } ZeroMemory(Buffer, Size); Packet = (PICMP_ECHO_PACKET)Buffer; /* Assemble ICMP echo request packet */ Packet->Icmp.Type = ICMPMSG_ECHOREQUEST; Packet->Icmp.Code = 0; Packet->Icmp.Id = (USHORT)GetCurrentProcessId(); Packet->Icmp.SeqNum = htons((USHORT)CurrentSeqNum); Packet->Icmp.Checksum = 0; /* Calculate checksum for ICMP header and data area */ Packet->Icmp.Checksum = Checksum((PUSHORT)&Packet->Icmp, sizeof(ICMP_ECHO_PACKET) + DataSize); CurrentSeqNum++; /* Send ICMP echo request */ FD_ZERO(&Fds); FD_SET(IcmpSock, &Fds); Timeval.tv_sec = Timeout / 1000; Timeval.tv_usec = Timeout % 1000; Status = select(0, NULL, &Fds, NULL, &Timeval); if ((Status != SOCKET_ERROR) && (Status != 0)) { #ifndef NDEBUG printf("Sending packet\n"); DisplayBuffer(Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize); printf("\n"); #endif /* !NDEBUG */ Status = sendto(IcmpSock, (const char *)Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize, 0, (SOCKADDR*)&Target, sizeof(Target)); QueryTime(&SentTime); SentCount++; } if (Status == SOCKET_ERROR) { if (WSAGetLastError() == WSAEHOSTUNREACH) printf("目标主机不可到达。\n\0"); else printf("无法发送数据 (%1!d!)。\n\0", WSAGetLastError()); GlobalFree(Buffer); return FALSE; } /* Expect to receive ICMP echo reply */ FD_ZERO(&Fds); FD_SET(IcmpSock, &Fds); Timeval.tv_sec = Timeout / 1000; Timeval.tv_usec = Timeout % 1000; do { Status = select(0, &Fds, NULL, NULL, &Timeval); if ((Status != SOCKET_ERROR) && (Status != 0)) { Length = sizeof(From); Status = recvfrom(IcmpSock, (char *)Buffer, Size, 0, &From, &Length); #ifndef NDEBUG printf("Received packet\n"); DisplayBuffer(Buffer, Status); printf("\n"); #endif /* !NDEBUG */ } else LostCount++; if (Status == SOCKET_ERROR) { if (WSAGetLastError() != WSAETIMEDOUT) { printf("无法接收数据 (%1!d!)。\n\0", WSAGetLastError()); GlobalFree(Buffer); return FALSE; } Status = 0; } if (Status == 0) { printf("请求超时。\n\0"); GlobalFree(Buffer); return TRUE; } } while (!DecodeResponse((char*)Buffer, Status, (PSOCKADDR_IN)&From)); GlobalFree(Buffer); return TRUE; } /* Program entry point */ int wmain(int argc, LPWSTR argv[]) { UINT Count; WCHAR MinTime[20]; WCHAR MaxTime[20]; WCHAR AvgTime[20]; hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); Reset(); if ((ParseCmdline(argc, argv)) && (Setup())) { printf("\n正在呼叫 %1 [%2] ,数据包大小 %3!d! 字节:\n\n\0", TargetName, TargetIP, DataSize); Count = 0; while ((NeverStop) || (Count < PingCount)) { Ping(); Count++; if((NeverStop) || (Count < PingCount)) Sleep(Timeout); }; Cleanup(); /* Calculate avarage round trip time */ if ((SentCount - LostCount) > 0) AvgRTT.QuadPart = SumRTT.QuadPart / (SentCount - LostCount); else AvgRTT.QuadPart = 0; /* Calculate loss percent */ Count = SentCount ? (LostCount * 100) / SentCount : 0; if (!MinRTTSet) MinRTT = MaxRTT; TimeToMsString(MinTime, MinRTT); TimeToMsString(MaxTime, MaxRTT); TimeToMsString(AvgTime, AvgRTT); /* Print statistics */ printf("\n%1 的呼叫统计:\n\0", TargetIP); printf(" 数据包:发送个数 = %1!d!,接收个数 = %2!d!,丢失个数 = %3!d! (丢失率 %4!d!%%),\n\0",\ SentCount, SentCount - LostCount, LostCount, Count); /* Print approximate times or NO approximate times if 100% loss */ if ((SentCount - LostCount) > 0) { printf("近似来回所需时间(毫秒):\n\0"); printf(" 最小值 = %1, 最大值 = %2, 平均值 = %3\n\0", MinTime, MaxTime, AvgTime); } } else { return 1; } return 0; } /* EOF */
标签: isp
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点!
本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。
上一篇:php过滤html标签
最新资讯
热门推荐