引言
ICMP(Internet Control Message Protocol,互聯網把持消息協定)是TCP/IP協定族的一個子協定,它重要用於在IP主機、路由器之間轉達把持消息。其中,ping命令就是基於ICMP協定實現的,它是一種常用的收集診斷東西,用於檢測收集連通性、測量收集耽誤跟丟包情況。本文將深刻探究怎樣利用C言語實現icmp ping,幫助讀者控制收集診斷利器。
ICMP協定簡介
1. ICMP協定概述
ICMP協定重要擔任在收集中轉達把持消息,如目標弗成達、超時、重定向等。它是一種無連接的協定,不保證數據包的堅固傳輸。
2. ICMP消息範例
ICMP消息範例重要包含以下多少種:
- Echo Request(範例8):用於發送ping懇求,並接收ping呼應。
- Echo Reply(範例0):用於呼應ping懇求。
- Destination Unreachable(範例3):當目標弗成達時發送。
- Time Exceeded(範例11):當數據包超不時發送。
C言語實現icmp ping
1. 情況籌備
在開端編寫代碼之前,須要籌備以下情況:
- 操縱體系:Windows或Linux
- 編譯器:MinGW-GCC或GCC
- 收集編程庫:Winsock(Windows)或libsocket(Linux)
2. 代碼構造
一個簡單的icmp ping順序平日包含以下文件:
icmphd.h
:定義ICMP頭部構造體。icmphd.c
:實現ICMP頭部構造體的相幹函數。main.c
:主函數進口。
3. 代碼實現
以下是一個簡單的icmp ping順序示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/icmp.h>
#define ICMP_ECHO_REQUEST 8
#define ICMP_ECHO_REPLY 0
void send_ping(const char *dest_ip) {
int sock;
struct sockaddr_in dest_addr;
struct iphdr *ip_header;
struct icmphdr *icmp_header;
char buffer[1024];
unsigned int seq = 1;
// 創建套接字
sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock < 0) {
perror("socket");
exit(1);
}
// 設置目標地點
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr(dest_ip);
// 構造ICMP頭部
ip_header = (struct iphdr *)buffer;
icmp_header = (struct icmphdr *)(buffer + sizeof(struct iphdr));
ip_header->version = 4;
ip_header->ihl = 5;
ip_header->tos = 0;
ip_header->id = htons(54321);
ip_header->tot_len = htons(64);
ip_header->frag_off = 0;
ip_header->ttl = 255;
ip_header->protocol = IPPROTO_ICMP;
ip_header->saddr = inet_addr("192.168.1.1"); // 當地IP地點
ip_header->daddr = dest_addr.sin_addr.s_addr;
icmp_header->type = ICMP_ECHO_REQUEST;
icmp_header->code = 0;
icmp_header->checksum = 0;
icmp_header->id = htons(1234);
icmp_header->seq = htons(seq);
// 打算校驗跟
icmp_header->checksum = calculate_checksum((unsigned short *)icmp_header, sizeof(struct icmphdr));
// 發送ICMP懇求
sendto(sock, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
printf("ICMP request sent to %s\n", dest_ip);
// 接收ICMP呼應
struct sockaddr_in sender_addr;
socklen_t sender_addr_len = sizeof(sender_addr);
int recv_len;
struct iphdr *recv_ip_header;
struct icmphdr *recv_icmp_header;
while ((recv_len = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&sender_addr, &sender_addr_len)) > 0) {
recv_ip_header = (struct iphdr *)buffer;
recv_icmp_header = (struct icmphdr *)(buffer + sizeof(struct iphdr));
if (recv_ip_header->protocol == IPPROTO_ICMP && recv_icmp_header->type == ICMP_ECHO_REPLY) {
printf("ICMP reply from %s: time=%ld ms\n", inet_ntoa(sender_addr.sin_addr), recvfrom_time);
}
}
close(sock);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <destination_ip>\n", argv[0]);
exit(1);
}
send_ping(argv[1]);
return 0;
}
4. 編譯與運轉
在編譯時,須要增加須要的庫文件。以下是編譯命令示例:
gcc -o ping ping.c -lws2_32
運轉順序,輸入目標IP地點:
./ping 8.8.8.8
總結
經由過程以上步調,我們可能利用C言語輕鬆實現icmp ping順序。控制icmp ping的實現道理,有助於我們更好地懂得收集通信過程,並處理收集成績。在現實利用中,可能根據須要增加更多功能,如自定義數據包大小、超不時光等。