首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 實作 ICMP Ping:封裝 IcmpSendEcho 打造跨平台網路連通性檢測類

     編輯:關於C++

Windows 原生不提供 ping 函數,需呼叫 **ICMP DLL (ICMPAPI)** 中的 IcmpSendEcho。本文封裝一個 CIcmpEcho 類別 (繼承 CSocket),提供主機名解析、IP 字串轉換、同步 Ping 延遲測量四大核心功能,可直接整合至 MFC/BCB/純 Win32 專案。

必要檔案與專案設定

  • 標頭檔:ipexport.h, icmpapi.h (Windows SDK 內建)。
  • 連結庫:icmp.lib (或動態載入 icmp.dll)。
  • 專案加入上述檔案,或安裝 Windows SDK 確保標頭可用。

類別介面設計

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 逾時或失敗"));
}

進階擴充建議

  • 非同步 Ping:搭配 IcmpSendEcho2 + 完成例程 / I/O 完成埠,支援大量並發監控。
  • IPv6 支援:使用 Icmp6CreateFile / Icmp6SendEcho2 (Vista+),傳入 sockaddr_in6。
  • 負載資料與序號:傳送自訂資料驗證回覆完整性,偵測封包竄改。
  • 權限處理:原始 Socket/ICMP 需管理員權限或 SeDebugPrivilege;一般用戶可改用 WSAIoctl(SIO_ICMP_ECHO) (受限)。

常見錯誤碼對照 (IcmpSendEcho 回傳值)

回傳值意義
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) 做多層次連通性判斷。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved