我在MSDN here中修改了此代码示例。如果我单独构建它,它工作正常,但如果我将它添加到我的应用程序,它会失败。为方便起见,我包括了我所拥有的课程的精确改编。
我只想每秒做一次简单的ping。原始套接字无法在没有管理员权限的情况下工作,而且这种ICMP.dll方法在我的应用程序中不起作用,我不明白为什么。错误183沿着"不能创建文件,因为它已经存在"在这种背景下没有任何意义。
有人能发现问题吗?非常感谢你的帮助。
Ping.h
#pragma once
#include "Ping.h"
#include "LogBase.h"
class WinPing :
public Ping
{
public:
WinPing(char* address, int period);
~WinPing();
unsigned long GetRTT();
private:
HANDLE _hIcmpFile;
unsigned long _ipaddr;
DWORD _dwRetVal;
LPVOID _replyBuffer;
DWORD _replySize;
static HANDLE _inputTimer;
int _period;
unsigned long _lastRTT;
static DWORD WINAPI AsyncPingHandler(void* Param);
void DoPing();
};
WinPing.h
#pragma once
#include "Ping.h"
#include "LogBase.h"
class WinPing :
public Ping
{
public:
WinPing(char* address, int period);
~WinPing();
unsigned long GetRTT();
private:
HANDLE _hIcmpFile;
unsigned long _ipaddr;
DWORD _dwRetVal;
LPVOID _replyBuffer;
DWORD _replySize;
static HANDLE _inputTimer;
int _period;
unsigned long _lastRTT;
static DWORD WINAPI AsyncPingHandler(void* Param);
void DoPing();
};
WinPing.cpp
#include "WinPing.h"
#include <winsock2.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <stdio.h>
#include "utils.h"
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
HANDLE WinPing::_inputTimer = NULL;
char SendData[32] = "Data Buffer";
unsigned long WinPing::GetRTT()
{
return _lastRTT;
}
void WinPing::DoPing()
{
LARGE_INTEGER t;
t.HighPart = t.LowPart = 0;
SetWaitableTimer(_inputTimer, &t, _period, NULL, NULL, TRUE);
while (true)
{
int r = WaitForSingleObject(_inputTimer, _period * 2);
if (r != WAIT_OBJECT_0)
{
LogLog("InputHandler: Bad Timer return", LogError);
}
_dwRetVal = IcmpSendEcho(_hIcmpFile, _ipaddr, SendData, sizeof(SendData),
NULL, _replyBuffer, _replySize, 1000);
if (_dwRetVal != 0) {
PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)_replyBuffer;
struct in_addr ReplyAddr;
ReplyAddr.S_un.S_addr = pEchoReply->Address;
LogLog("\tSent icmp message to %s\n", LogDebug, _address);
if (_dwRetVal > 1) {
LogLog("\tReceived %ld icmp message responses\n", LogDebug, _dwRetVal);
LogLog("\tInformation from the first response:\n", LogDebug);
}
else {
LogLog("\tReceived %ld icmp message response\n", LogDebug, _dwRetVal);
LogLog("\tInformation from this response:\n", LogDebug);
}
LogLog("\t Received from %s\n", LogDebug, inet_ntoa(ReplyAddr));
LogLog("\t Status = %ld\n", LogDebug,
pEchoReply->Status);
LogLog("\t Roundtrip time = %ld milliseconds\n", LogDebug,
pEchoReply->RoundTripTime);
//needs synchronization here. Probably not very important
_lastRTT = pEchoReply->RoundTripTime;
LogLog("\t Roundtrip time = %ld milliseconds\n", LogDebug, _lastRTT);
IcmpCloseHandle(_hIcmpFile);
}
else {
LogLog("\tCall to IcmpSendEcho failed.\n", LogError);
LogLog("\tIcmpSendEcho returned error: %ld\n", LogError, GetLastError());
}
}
}
DWORD WINAPI WinPing::AsyncPingHandler(void* Param)
{
_inputTimer = CreateWaitableTimer(NULL, false, NULL);
if (!_inputTimer)
{
LogLog("Unable to create input waitable timer", LogError);
return 1;
}
LogLog("RTT Ping Thread started", LogDebug);
WinPing* This = (WinPing*)Param;
This->DoPing();
return 0;
}
WinPing::WinPing(char* address, int period)
:Ping(address),
_period(period)
{
// Declare and initialize variables
_ipaddr = INADDR_NONE;
_dwRetVal = 0;
_replyBuffer = NULL;
_replySize = 0;
_ipaddr = inet_addr(address);
if (_ipaddr == INADDR_NONE) {
LogLog("Not an IP Address:%s", LogError, address);
return;
}
_hIcmpFile = IcmpCreateFile();
if (_hIcmpFile == INVALID_HANDLE_VALUE) {
LogLog("\tUnable to open handle.\n", LogError);
LogLog("IcmpCreatefile returned error: %ld\n", LogError, GetLastError());
return;
}
_replySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
_replyBuffer = (VOID*)malloc(_replySize);
if (_replyBuffer == NULL) {
LogLog("\tUnable to allocate memory\n", LogError);
return;
}
//Spawn thread on AsyncPingHandler()
CreateClassThread(AsyncPingHandler, this);
}
WinPing::~WinPing()
{
}
答案 0 :(得分:1)
GetLastError()
失败后,您没有立即致电IcmpSendEcho()
(调用IcmpCreateFile()
时也是如此)。您首先调用LogLog()
,这可能会更改GetLastError()
返回的错误代码,例如,如果它正在记录到无法找到的文件。 始终在执行可能调用系统函数的任何操作之前调用GetLastError()
。
else {
DWORD dwErrCode = GetLastError(); // <-- call GetLastError() first
LogLog("\tCall to IcmpSendEcho failed.\n", LogError);
LogLog("\tIcmpSendEcho returned error: %u\n", LogError, dwErrCode); // <-- then use the value when needed
return;
}
答案 1 :(得分:1)
我发现使用GetRTTandHopCount更简单,更稳定的ping方式。这是一个例子。
UINT ip = inet_addr(serverAddress);
ULONG hopCount = 0;
ULONG RTT = 0;
if (GetRTTAndHopCount(ip, &hopCount, 30, &RTT) == TRUE) {
printf("Hops: %ld\n", hopCount);
printf("RTT: %ld\n", RTT);
}
else {
printf("Error: %ld\n", GetLastError());
}
return RTT;