Windows 原生不提供 ping 函數,需呼叫 **ICMP DLL (ICMPAPI)** 中的 IcmpSendEcho。本文封裝一個 CIcmpEcho 類別 (繼承 CSocket),提供主機名解析、IP 字串轉換、同步 Ping 延遲測量四大核心功能,可直接整合至 MFC/BCB/純 Win32 專案。
ipexport.h, icmpapi.h (Windows SDK 內建)。icmp.lib (或動態載入 icmp.dll)。class CIcmpEcho : public CSocket {
public:
CIcmpEcho();
virtual ~CIcmpEcho();
// 字串 IP (如 "192.168.1.1") 轉網序 DWORD
unsigned long ResolveIP(CString strIP);
// 主機名 (如 "www.google.com") 經 DNS/WINS 解析為網序 DWORD
unsigned long ResolveName(CString strHostName);
// 網序 DWORD 轉點分十進位字串
CString GetIP(unsigned long ulIP);
// 核心:Ping 指定 IP,傳回往返時間 (ms),失敗回傳 0xFFFFFFFF
DWORD PingHost(unsigned long ulIP, int iTimeoutMs = 1000);
};
unsigned long CIcmpEcho::ResolveIP(CString strIP)
{
return inet_addr(strIP); // 已為網序
}
unsigned long CIcmpEcho::ResolveName(CString strHostName)
{
hostent* pHost = gethostbyname(strHostName);
if (!pHost) return 0;
return *(DWORD*)(*pHost->h_addr_list); // 第一個 IPv4 位址
}
CString CIcmpEcho::GetIP(unsigned long ulIP)
{
in_addr addr; addr.s_addr = ulIP;
return CString(inet_ntoa(addr));
}
DWORD CIcmpEcho::PingHost(unsigned long ulIP, int iTimeoutMs)
{
HANDLE hIcmp = IcmpCreateFile();
if (hIcmp == INVALID_HANDLE_VALUE) return 0xFFFFFFFF;
// 回覆緩衝區需包含 ICMP_ECHO_REPLY + 選項資料空間
BYTE replyBuf[sizeof(ICMP_ECHO_REPLY) + 8];
PICMP_ECHO_REPLY pReply = (PICMP_ECHO_REPLY)replyBuf;
pReply->RoundTripTime = 0xFFFFFFFF;
// 發送 ICMP Echo Request (無負載資料)
IcmpSendEcho(hIcmp, ulIP, nullptr, 0, nullptr, replyBuf, sizeof(replyBuf), iTimeoutMs);
DWORD rtt = pReply->RoundTripTime;
IcmpCloseHandle(hIcmp);
return rtt; // 0xFFFFFFFF 表示逾時/失敗
}
CIcmpEcho ping;
CString host = _T("www.example.com");
DWORD ip = ping.ResolveName(host);
if (ip) {
DWORD rtt = ping.PingHost(ip, 2000);
if (rtt != 0xFFFFFFFF)
AfxMessageBox(CString().Format(_T("%s (%s) Ping: %u ms"), host, ping.GetIP(ip), rtt));
else
AfxMessageBox(_T("Ping 逾時或失敗"));
}
IcmpSendEcho2 + 完成例程 / I/O 完成埠,支援大量並發監控。Icmp6CreateFile / Icmp6SendEcho2 (Vista+),傳入 sockaddr_in6。SeDebugPrivilege;一般用戶可改用 WSAIoctl(SIO_ICMP_ECHO) (受限)。| 回傳值 | 意義 |
|---|---|
| 0 | 發送失敗,呼叫 GetLastError() 取得詳細碼 |
| >0 | 收到回覆封包數 |
| RoundTripTime = 0xFFFFFFFF | 逾時或目的主機不可達 |
| IP_REQ_TIMED_OUT (11010) | 逾時 |
| IP_DEST_NET_UNREACHABLE (11002) | 網路不可達 |
| IP_TTL_EXPIRED_TRANSIT (11013) | TTL 過期 |
封裝 IcmpSendEcho 即可在 C++ 專案中輕鬆實現 Ping 功能。注意 ICMP 屬於原始通訊協定,部分防火牆/雲端環境會封鎖 ICMP Echo,建議搭配 TCP/UDP 連線測試 (如連接 Port 80/443) 做多層次連通性判斷。