MFC C++:IcmpSendEcho 成功返回,但状态为 IP_DEST_HOST_UNREACHABLE,并且 R

MFC C++ : IcmpSendEcho returns successfully, but status is IP_DEST_HOST_UNREACHABLE and RoundTripTime is not the default timeout time

本文关键字:IP DEST HOST 并且 UNREACHABLE 状态 C++ IcmpSendEcho 成功 返回 MFC      更新时间:2023-10-16

我在程序中使用IcmpSendEcho来检查与内部网络中IP地址对应的特定PC是否打开。此解决方案几乎适用于所有客户,但其中一个客户的情况非常不寻常。

我当然知道这台特定的计算机(顺便说一下,它发生在多台计算机上)是 24/7 全天候运行的,但IcmpSendEcho行为在白天会发生变化,我不明白为什么。

在时间段 05:00 AM - 08:00 PM 期间,此计算机上的IcmpSendEcho返回成功的回显请求 (IP_SUCCESS),具有合理的往返时间,但在时间段 08:00 PM - 05:00 AM 期间,IcmpSendEcho 返回错误IP_DEST_HOST_UNREACHABLE。奇怪的是,往返时间与分配给 IcmpSendEcho函数的超时时间不对应,而是更低。

如果我在关闭的计算机上执行测试,我的代码会告诉我IcmpSendEcho请求失败,因此代码转到不同的指令块。

为什么会这样?IcmpSendEcho请求失败和成功但错误代码如IP_DEST_HOST_UNREACHABLE有什么区别?

谢谢你的帮助。

unsigned long ipaddr = inet_addr(CT2CA(myIpAddress));
HANDLE hIcmpFile;
hIcmpFile = IcmpCreateFile();
if (hIcmpFile == INVALID_HANDLE_VALUE) {
printf("tUnable to open handle.n");
printf("IcmpCreatefile returned error: %ldn", GetLastError());
EDMLog::Error(_T("Unable to open handle. error code 001"));
errorCode = _T("001");
}
else {
char SendData[100];
for (int x = 0; x < 100; ++x) {
SendData[x] = 'A';
}
LPVOID ReplyBuffer = NULL;
DWORD ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
ReplyBuffer = (VOID*)malloc(ReplySize);
if (ReplyBuffer == NULL) {
printf("tUnable to allocate memoryn");
EDMLog::Error(_T("Unable to allocate memory. error code 001"));
errorCode = _T("001");
}
else {
DWORD dwRetVal = IcmpSendEcho(hIcmpFile, ipaddr, SendData, sizeof(SendData),
NULL, ReplyBuffer, ReplySize, 10000);
printf("tSent icmp message to %sn", CT2CA(myIpAddress);
EDMLog::Information(_T("Test su indirizzo ") + myIpAddress);
if (dwRetVal != 0) {
/////////////////////////////////////
//HERE THE REQUEST IS SUCCESSFULL BUT THE ERROR CODE IS IP_DEST_HOST_UNREACHABLE
/////////////////////////////////////
PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
struct in_addr ReplyAddr;
ReplyAddr.S_un.S_addr = pEchoReply->Address;
if (dwRetVal > 1) {
printf("tReceived %ld icmp message responsesn", dwRetVal);
printf("tInformation from the first response:n");
}
else {
printf("tReceived %ld icmp message responsen", dwRetVal);
printf("tInformation from this response:n");
}
printf("t  Received from %sn", inet_ntoa(ReplyAddr));
printf("t  Status = %ldn",
pEchoReply->Status);
switch (pEchoReply->Status) {
case IP_SUCCESS:
//GESTIONE PARTICOLARE PER GAROM
//errorCode.Format(_T("90%d"), i + 1);
//GESTIONE TRADIZIONALE
errorCode = _T("000");
EDMLog::Debug(_T("Test eseguito correttamente."));
break;
case IP_BUF_TOO_SMALL:
EDMLog::Error(_T("Buffer too small. error code 101"));
errorCode = _T("101");
break;
case IP_DEST_NET_UNREACHABLE:
EDMLog::Error(_T("DEST NET UNREACHABLE. error code 102"));
errorCode = _T("102");
break;
case IP_DEST_HOST_UNREACHABLE:
EDMLog::Error(_T("DEST HOST UNREACHABLE. error code 103"));
errorCode = _T("103");
break;
case IP_DEST_PROT_UNREACHABLE:
EDMLog::Error(_T("DEST PROT UNREACHABLE. error code 104"));
errorCode = _T("104");
break;
case IP_DEST_PORT_UNREACHABLE:
EDMLog::Error(_T("DEST PORT UNREACHABLE. error code 105"));
errorCode = _T("105");
break;
case IP_NO_RESOURCES:
EDMLog::Error(_T("IP NO RESOURCES. error code 106"));
errorCode = _T("106");
break;
case IP_BAD_OPTION:
EDMLog::Error(_T("IP BAD OPTION. error code 107"));
errorCode = _T("107");
break;
case IP_HW_ERROR:
EDMLog::Error(_T("IP HW ERROR. error code 108"));
errorCode = _T("108");
break;
case IP_PACKET_TOO_BIG:
EDMLog::Error(_T("IP PACKET TOO BIG. error code 109"));
errorCode = _T("109");
break;
case IP_REQ_TIMED_OUT:
EDMLog::Error(_T("IP REQ TIMED OUT. error code 110"));
errorCode = _T("110");
break;
case IP_BAD_REQ:
EDMLog::Error(_T("IP BAD REQ. error code 111"));
errorCode = _T("111");
break;
case IP_BAD_ROUTE:
EDMLog::Error(_T("IP BAD ROUTE. error code 112"));
errorCode = _T("112");
break;
case IP_TTL_EXPIRED_TRANSIT:
EDMLog::Error(_T("IP TTL EXPIRED TRANSIT. error code 113"));
errorCode = _T("113");
break;
case IP_TTL_EXPIRED_REASSEM:
EDMLog::Error(_T("IP TTL EXPIRED REASSEM. error code 114"));
errorCode = _T("114");
break;
case IP_PARAM_PROBLEM:
EDMLog::Error(_T("IP PARAM PROBLEM. error code 115"));
errorCode = _T("115");
break;
case IP_SOURCE_QUENCH:
EDMLog::Error(_T("IP SOURCE QUENCH. error code 116"));
errorCode = _T("116");
break;
case IP_OPTION_TOO_BIG:
EDMLog::Error(_T("IP OPTION TOO BIG. error code 117"));
errorCode = _T("117");
break;
case IP_BAD_DESTINATION:
EDMLog::Error(_T("IP BAD DESTINATION. error code 118"));
errorCode = _T("118");
break;
case IP_GENERAL_FAILURE:
EDMLog::Error(_T("IP GENERAL FAILURE. error code 150"));
errorCode = _T("150");
break;
}
printf("t  Roundtrip time = %ld millisecondsn",
pEchoReply->RoundTripTime);
if ((int)(pEchoReply->RoundTripTime) == 0)
valore.Format(_T("%d"), 1);
else
valore.Format(_T("%d"),(int)(pEchoReply->RoundTripTime));
}
else {
/////////////////////////////////////
//HERE THE REQUEST IS NOT SUCCESSFUL (TIMEOUT)
/////////////////////////////////////
printf("tCall to IcmpSendEcho failed.n");
DWORD lastError = GetLastError();
printf("tIcmpSendEcho returned error: %ldn", lastError);

PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY)ReplyBuffer;
struct in_addr ReplyAddr;
ReplyAddr.S_un.S_addr = pEchoReply->Address;
if (dwRetVal > 1) {
printf("tReceived %ld icmp message responsesn", dwRetVal);
printf("tInformation from the first response:n");
}
else {
printf("tReceived %ld icmp message responsen", dwRetVal);
printf("tInformation from this response:n");
}
printf("t  Received from %sn", inet_ntoa(ReplyAddr));
printf("t  Status = %ldn",
pEchoReply->Status);
valore = _T("0");
switch (pEchoReply->Status) {
case IP_SUCCESS:
errorCode = _T("000");
EDMLog::Information(_T("Test eseguito correttamente."));
break;
case IP_BUF_TOO_SMALL:
EDMLog::Error(_T("Buffer too small. error code 101"));
errorCode = _T("101");
break;
case IP_DEST_NET_UNREACHABLE:
EDMLog::Error(_T("DEST NET UNREACHABLE. error code 102"));
errorCode = _T("102");
break;
case IP_DEST_HOST_UNREACHABLE:
EDMLog::Error(_T("DEST HOST UNREACHABLE. error code 103"));
errorCode = _T("103");
break;
case IP_DEST_PROT_UNREACHABLE:
EDMLog::Error(_T("DEST PROT UNREACHABLE. error code 104"));
errorCode = _T("104");
break;
case IP_DEST_PORT_UNREACHABLE:
EDMLog::Error(_T("DEST PORT UNREACHABLE. error code 105"));
errorCode = _T("105");
break;
case IP_NO_RESOURCES:
EDMLog::Error(_T("IP NO RESOURCES. error code 106"));
errorCode = _T("106");
break;
case IP_BAD_OPTION:
EDMLog::Error(_T("IP BAD OPTION. error code 107"));
errorCode = _T("107");
break;
case IP_HW_ERROR:
EDMLog::Error(_T("IP HW ERROR. error code 108"));
errorCode = _T("108");
break;
case IP_PACKET_TOO_BIG:
EDMLog::Error(_T("IP PACKET TOO BIG. error code 109"));
errorCode = _T("109");
break;
case IP_REQ_TIMED_OUT:
EDMLog::Error(_T("IP REQ TIMED OUT. error code 110"));
errorCode = _T("004");
valore = _T("10000");
break;
case IP_BAD_REQ:
EDMLog::Error(_T("IP BAD REQ. error code 111"));
errorCode = _T("111");
break;
case IP_BAD_ROUTE:
EDMLog::Error(_T("IP BAD ROUTE. error code 112"));
errorCode = _T("112");
break;
case IP_TTL_EXPIRED_TRANSIT:
EDMLog::Error(_T("IP TTL EXPIRED TRANSIT. error code 113"));
errorCode = _T("113");
break;
case IP_TTL_EXPIRED_REASSEM:
EDMLog::Error(_T("IP TTL EXPIRED REASSEM. error code 114"));
errorCode = _T("114");
break;
case IP_PARAM_PROBLEM:
EDMLog::Error(_T("IP PARAM PROBLEM. error code 115"));
errorCode = _T("115");
break;
case IP_SOURCE_QUENCH:
EDMLog::Error(_T("IP SOURCE QUENCH. error code 116"));
errorCode = _T("116");
break;
case IP_OPTION_TOO_BIG:
EDMLog::Error(_T("IP OPTION TOO BIG. error code 117"));
errorCode = _T("117");
break;
case IP_BAD_DESTINATION:
EDMLog::Error(_T("IP BAD DESTINATION. error code 118"));
errorCode = _T("118");
break;
case IP_GENERAL_FAILURE:
EDMLog::Error(_T("IP GENERAL FAILURE. error code 150"));
errorCode = _T("150");
break;
}
}
IcmpCloseHandle(hIcmpFile);
}
}

显然,上述代码的任何改进都受到好评,再次感谢您。

问题是如何解析地址。对于PC在同一局域网中的情况,需要根据目标IP地址获取MAC地址。它使用 ARP 协议,无法获取 MAC 地址,因此无法发送 ICMP 消息。然后它可能会尊重超时。它将在超时时放弃。在另一种情况下,如果要将回显请求 ICMP 消息发送到 LAN 外部的节点,则该消息将通过中间路由器(也可以是网关)进行路由。因此,传达 ICMP 消息的 IP 数据包将离开您的 PC 到下一跳,在下一跳之外的某个地方,路由器将意识到如果无法路由该 ICMP 数据包,它将返回 ICMP 消息目的地无法访问到源节点(您的 PC)。当ping收到此消息时,等待超时是没有意义的,它已经收到一条消息,告诉它目的地无法访问。

Gotcha。路由器有一个规则,可以阻止从一小时到另一个小时的任何类型的流量。显然,客户没有告诉我这件事。谢谢大家!