本文提供一個跨平台(Windows/Linux)的 ping 核心實現,使用原始 Socket (SOCK_RAW, IPPROTO_ICMP) 手工構造 IPv4 頭部與 ICMP 回顯請求報文,演示校驗和計算、時間戳、序號、ID、TTL 等關鍵字段處理,是學習網絡協議編程的極佳教具。
type(1) code(1) checksum(2) id(2) seq(2) timestamp(4) + 可選數據。// 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;
}
socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)(需 root/Admin 權限)。sendto 發送至目標 IP。recvfrom 接收回應(含 IP 頭部),解析 IP 頭部長度 (ihl*4),定位 ICMP 頭部。Reply from IP: bytes=... time=...ms TTL=... seq=...。| 項目 | Windows | Linux |
|---|---|---|
| 頭文件 | <winsock.h> + Wsock32.lib | <sys/socket.h>, <netinet/ip_icmp.h> |
| Socket 初始化 | WSAStartup | 無 |
| 進程 ID | GetCurrentProcessId() | 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 權限