c语言实现ping(c语言实现ping程序)

# 简介`ping` 是一个广泛使用的网络工具,用于测试主机之间的连通性。它通过发送 ICMP(Internet Control Message Protocol)回显请求消息并等待回显应答来判断目标主机是否可达。在 C 语言中,我们可以通过使用系统调用和套接字接口来实现类似的功能。本文将详细介绍如何使用 C 语言实现一个简单的 `ping` 工具。---## 1. 需求分析与设计### 1.1 功能需求 - 发送 ICMP 回显请求包。 - 接收并解析 ICMP 响应包。 - 计算并显示延迟时间。 - 支持指定目标地址和发送次数。### 1.2 技术选型 - 使用 `socket` 创建原始套接字。 - 利用 `ioctl` 获取本地 IP 地址。 - 使用 `time.h` 库计算延迟时间。 - 处理 ICMP 协议相关的数据结构。---## 2. 实现步骤### 2.1 初始化套接字 为了发送 ICMP 包,我们需要创建一个原始套接字。原始套接字允许程序直接操作网络层协议(如 ICMP),而无需经过传输层协议栈。```c #include #include #include #include #include #include int create_socket() {int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);if (sockfd < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}return sockfd; } ```### 2.2 构造 ICMP 数据包 ICMP 回显请求包由一个类型字段(8 字节)、代码字段(8 字节)和校验和字段(16 字节)组成。此外,还需要填充可选的数据部分。```c #define ICMP_ECHO_REQUEST 8typedef struct icmp_hdr {unsigned char type; // 类型unsigned char code; // 代码unsigned short checksum; // 校验和unsigned short id; // 标识符unsigned short seq; // 序列号 } icmp_hdr;void build_icmp_packet(icmp_hdr

icmp, unsigned short id, unsigned short seq) {icmp->type = ICMP_ECHO_REQUEST;icmp->code = 0;icmp->id = htons(id);icmp->seq = htons(seq);// 计算校验和unsigned short

ptr = (unsigned short

)icmp;size_t len = sizeof(icmp_hdr) / 2;unsigned long sum = 0;while (len > 0) {sum +=

ptr++;len--;}sum = (sum >> 16) + (sum & 0xffff);sum += (sum >> 16);icmp->checksum = ~((unsigned short)sum); } ```### 2.3 发送与接收数据包 使用 `sendto` 函数发送 ICMP 请求包,并通过 `recvfrom` 接收响应包。```c void send_and_receive(int sockfd, const char

target_ip, int seq) {struct sockaddr_in dest_addr;memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family = AF_INET;dest_addr.sin_addr.s_addr = inet_addr(target_ip);icmp_hdr icmp;build_icmp_packet(&icmp, getpid(), seq);ssize_t sent_bytes = sendto(sockfd, &icmp, sizeof(icmp), 0, (struct sockaddr

)&dest_addr, sizeof(dest_addr));if (sent_bytes < 0) {perror("Send failed");return;}struct timeval start_time, end_time;gettimeofday(&start_time, NULL);char recv_buf[sizeof(icmp_hdr) + 1024];socklen_t addr_len = sizeof(dest_addr);ssize_t received_bytes = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr

)&dest_addr, &addr_len);if (received_bytes < 0) {perror("Receive failed");return;}gettimeofday(&end_time, NULL);double elapsed_time = (end_time.tv_sec - start_time.tv_sec)

1000.0 +(end_time.tv_usec - start_time.tv_usec) / 1000.0;printf("Reply from %s: time=%.3f ms\n", target_ip, elapsed_time); } ```### 2.4 主函数逻辑 主函数负责初始化套接字、解析目标地址以及循环发送 ICMP 包。```c int main(int argc, char

argv) {if (argc != 2) {fprintf(stderr, "Usage: %s \n", argv[0]);exit(EXIT_FAILURE);}const char

target_ip = argv[1];int sockfd = create_socket();for (int i = 1; i <= 4; i++) { // 默认发送 4 次send_and_receive(sockfd, target_ip, i);}close(sockfd);return 0; } ```---## 3. 测试与验证编译上述代码后运行程序,例如:```bash gcc -o ping ping.c ./ping www.google.com ```输出示例: ``` Reply from 172.217.160.174: time=5.234 ms Reply from 172.217.160.174: time=6.123 ms Reply from 172.217.160.174: time=4.987 ms Reply from 172.217.160.174: time=5.567 ms ```---## 4. 总结通过本篇文章,我们了解了如何使用 C 语言实现一个简单的 `ping` 工具。虽然这个版本功能较为基础,但它展示了如何利用原始套接字和 ICMP 协议进行网络通信的基本原理。如果需要进一步扩展,可以添加更多功能,比如支持 IPv6、更复杂的错误处理等。

简介`ping` 是一个广泛使用的网络工具,用于测试主机之间的连通性。它通过发送 ICMP(Internet Control Message Protocol)回显请求消息并等待回显应答来判断目标主机是否可达。在 C 语言中,我们可以通过使用系统调用和套接字接口来实现类似的功能。本文将详细介绍如何使用 C 语言实现一个简单的 `ping` 工具。---

1. 需求分析与设计

1.1 功能需求 - 发送 ICMP 回显请求包。 - 接收并解析 ICMP 响应包。 - 计算并显示延迟时间。 - 支持指定目标地址和发送次数。

1.2 技术选型 - 使用 `socket` 创建原始套接字。 - 利用 `ioctl` 获取本地 IP 地址。 - 使用 `time.h` 库计算延迟时间。 - 处理 ICMP 协议相关的数据结构。---

2. 实现步骤

2.1 初始化套接字 为了发送 ICMP 包,我们需要创建一个原始套接字。原始套接字允许程序直接操作网络层协议(如 ICMP),而无需经过传输层协议栈。```c

include

include

include

include

include

include int create_socket() {int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);if (sockfd < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}return sockfd; } ```

2.2 构造 ICMP 数据包 ICMP 回显请求包由一个类型字段(8 字节)、代码字段(8 字节)和校验和字段(16 字节)组成。此外,还需要填充可选的数据部分。```c

define ICMP_ECHO_REQUEST 8typedef struct icmp_hdr {unsigned char type; // 类型unsigned char code; // 代码unsigned short checksum; // 校验和unsigned short id; // 标识符unsigned short seq; // 序列号 } icmp_hdr;void build_icmp_packet(icmp_hdr *icmp, unsigned short id, unsigned short seq) {icmp->type = ICMP_ECHO_REQUEST;icmp->code = 0;icmp->id = htons(id);icmp->seq = htons(seq);// 计算校验和unsigned short *ptr = (unsigned short *)icmp;size_t len = sizeof(icmp_hdr) / 2;unsigned long sum = 0;while (len > 0) {sum += *ptr++;len--;}sum = (sum >> 16) + (sum & 0xffff);sum += (sum >> 16);icmp->checksum = ~((unsigned short)sum); } ```

2.3 发送与接收数据包 使用 `sendto` 函数发送 ICMP 请求包,并通过 `recvfrom` 接收响应包。```c void send_and_receive(int sockfd, const char *target_ip, int seq) {struct sockaddr_in dest_addr;memset(&dest_addr, 0, sizeof(dest_addr));dest_addr.sin_family = AF_INET;dest_addr.sin_addr.s_addr = inet_addr(target_ip);icmp_hdr icmp;build_icmp_packet(&icmp, getpid(), seq);ssize_t sent_bytes = sendto(sockfd, &icmp, sizeof(icmp), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (sent_bytes < 0) {perror("Send failed");return;}struct timeval start_time, end_time;gettimeofday(&start_time, NULL);char recv_buf[sizeof(icmp_hdr) + 1024];socklen_t addr_len = sizeof(dest_addr);ssize_t received_bytes = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&dest_addr, &addr_len);if (received_bytes < 0) {perror("Receive failed");return;}gettimeofday(&end_time, NULL);double elapsed_time = (end_time.tv_sec - start_time.tv_sec) * 1000.0 +(end_time.tv_usec - start_time.tv_usec) / 1000.0;printf("Reply from %s: time=%.3f ms\n", target_ip, elapsed_time); } ```

2.4 主函数逻辑 主函数负责初始化套接字、解析目标地址以及循环发送 ICMP 包。```c int main(int argc, char **argv) {if (argc != 2) {fprintf(stderr, "Usage: %s \n", argv[0]);exit(EXIT_FAILURE);}const char *target_ip = argv[1];int sockfd = create_socket();for (int i = 1; i <= 4; i++) { // 默认发送 4 次send_and_receive(sockfd, target_ip, i);}close(sockfd);return 0; } ```---

3. 测试与验证编译上述代码后运行程序,例如:```bash gcc -o ping ping.c ./ping www.google.com ```输出示例: ``` Reply from 172.217.160.174: time=5.234 ms Reply from 172.217.160.174: time=6.123 ms Reply from 172.217.160.174: time=4.987 ms Reply from 172.217.160.174: time=5.567 ms ```---

4. 总结通过本篇文章,我们了解了如何使用 C 语言实现一个简单的 `ping` 工具。虽然这个版本功能较为基础,但它展示了如何利用原始套接字和 ICMP 协议进行网络通信的基本原理。如果需要进一步扩展,可以添加更多功能,比如支持 IPv6、更复杂的错误处理等。

标签列表