【掌握C语言,轻松实现icmp ping】揭秘网络诊断利器

发布时间:2025-05-24 21:27:34

引言

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的实现道理,有助于我们更好地懂得收集通信过程,并处理收集成绩。在现实利用中,可能根据须要增加更多功能,如自定义数据包大小、超不时光等。