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

C語言實現 Ping 功能:原始 Socket 構造 ICMP 回顯請求完整源碼

     編輯:關於C

本文提供一個跨平台(Windows/Linux)的 ping 核心實現,使用原始 Socket (SOCK_RAW, IPPROTO_ICMP) 手工構造 IPv4 頭部與 ICMP 回顯請求報文,演示校驗和計算、時間戳、序號、ID、TTL 等關鍵字段處理,是學習網絡協議編程的極佳教具。

核心協議知識(RFC 792)

  • ICMP 類型 8:Echo Request(請求);類型 0:Echo Reply(應答)。
  • ICMP 頭部:type(1) code(1) checksum(2) id(2) seq(2) timestamp(4) + 可選數據。
  • IPv4 頭部:版本、首部長度、TOS、總長度、標識、標誌/片偏移、TTL、協議(1=ICMP)、首部校驗和、源/目的 IP。
  • 校驗和算法:將報文視為 16 位字序列求反碼和(溢出回卷)。

關鍵數據結構

// IPv4 頭部(位域對齊)
typedef struct {
    unsigned char h_len:4, version:4;
    unsigned char tos;
    unsigned short total_len;
    unsigned short ident;
    unsigned short frag_flags;
    unsigned char ttl;
    unsigned char proto;
    unsigned short checksum;
    unsigned int srcIP, dstIP;
} IPHeader;

// ICMP 頭部
typedef struct {
    unsigned char type, code;
    unsigned short checksum;
    unsigned short id, seq;
    unsigned long timestamp;
} ICMPHeader;

校驗和計算函數

unsigned short in_cksum(unsigned short *addr, int len) {
    int nleft = len; int sum = 0; unsigned short *w = addr;
    while (nleft > 1) { sum += *w++; nleft -= 2; }
    if (nleft == 1) { unsigned short ans = 0; *(unsigned char*)&ans = *(unsigned char*)w; sum += ans; }
    sum = (sum >> 16) + (sum & 0xFFFF); sum += (sum >> 16);
    return ~sum;
}

發送與接收流程

  1. 創建原始 Socket:socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)(需 root/Admin 權限)。
  2. 填充 ICMP 請求:類型 8、ID=進程ID、序號遞增、時間戳=當前毫秒數、計算校驗和。
  3. sendto 發送至目標 IP。
  4. recvfrom 接收回應(含 IP 頭部),解析 IP 頭部長度 (ihl*4),定位 ICMP 頭部。
  5. 驗證類型 0、ID、序號匹配,計算 RTT = 當前時間 - 回報時間戳。
  6. 輸出:Reply from IP: bytes=... time=...ms TTL=... seq=...。

跨平台適配要點

項目WindowsLinux
頭文件<winsock.h> + Wsock32.lib<sys/socket.h>, <netinet/ip_icmp.h>
Socket 初始化WSAStartup無
進程 IDGetCurrentProcessId()getpid()
毫秒時間戳GetTickCount()time(NULL) 或 gettimeofday
清理WSACleanup()無

完整源碼結構(節選關鍵函數)

int main(int argc, char **argv) {
    // 參數解析:目標主機/IP、可選數據大小
    // 跨平台初始化
    // 解析主機名 gethostbyname / inet_addr
    // 創建 SOCK_RAW socket
    for (int i=0; i<3; i++) { // 發送 3 次
        fill_icmp_data(buf, datasize);     // 填充數據載荷
        fill_icmp_header(buf, datasize);   // 填充 ICMP 頭部、校驗和
        sendto(sockfd, buf, icmp_len, 0, (sockaddr*)&dest, sizeof(dest));
        recvfrom(sockfd, recv_buf, 1024, 0, (sockaddr*)&from, &fromlen);
        decode_ip_icmp(recv_buf, recv_len); // 解析並打印結果
    }
    // 清理
}

學習建議

「代碼本身意義有限,**核心價值在於理解 RFC 792 ICMP 協議細節**」。建議讀者對照 RFC 文檔,逐字段對應代碼,手動構造報文、抓包分析(Wireshark),才能真正掌握網絡協議編程精髓。

編譯運行

# Windows (VC/GCC)
cl xping.c /link Wsock32.lib
# 或 gcc xping.c -lws2_32 -o xping.exe

# Linux
gcc xping.c -o xping
sudo ./xping www.baidu.com  # 需 root 權限
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved