C 语言实现 ping 程序

本文介绍了如何使用C语言实现ping命令,详细讲解了ping命令涉及的TCP/IP协议,特别是ICMP协议的工作原理,以及ICMP报文的结构。文章还涵盖了地址信息表示、主机字节序与网络字节序的转换、相关函数的使用,以及校验和算法的实现。通过实例展示了如何创建原始套接字、封装ICMP报文并发送、接收响应报文的过程。
摘要由CSDN通过智能技术生成

C 语言实现 ping 程序

实验介绍

本项目学习用 C 语言实现 ping 命令。通过本项目中更深入地理解 TCP/IP 协议,掌握 C 语言进行网络编程的技巧方法。

一、ping 命令使用的相关 TCP/IP 协议介绍

ping 命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。例如,执行 ping 127.0.0.1 会得到如下结果:


由上面的执行结果可以看到,ping 命令执行后显示出被测试系统主机名和相应 IP 地址、返回给当前主机的 ICMP 报文顺序号、ttl 生存时间和往返时间 rtt(单位是毫秒,即千分之一秒)。

要真正了解 ping 命令实现原理,就要了解 ping 命令所使用到的 TCP/IP 协议:ICMP 协议。

ICMP 是(Internet Control Message Protocol)Internet 控制报文协议。它是 TCP/IP 协议族的一个子协议,用于在 IP 主机、路由器之间传递控制消息。

控制消息有:目的不可达消息,超时信息,重定向消息,时间戳请求和时间戳响应消息,回显请求和回显应答消息。

ping 命令使用回显请求和回显应答消息。具体表现是向网络上的另一个主机系统发送 ICMP 报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者。

下面来看下回显请求和回显应答消息 ICMP 报文格式:


回显请求报文其中类型为 0,代码为 0。

回显应答报文其中类型为 8,代码为 0。

校验和字段:包括数据在内的整个 ICMP 协议数据包的校验和,具体实现方法会在下面详细介绍。

标识符字段:用于唯一标识 ICMP 报文,本项目使用程序的进程 id。因为如果同时在两个命令行终端执行 ping 命令的话,每个 ping 命令都会接收到所有的回显应答,所以需要根据标识符来判断回显应答是否应该接收。

序号字段:ICMP 报文的序号。

数据字段:也就是报文,本项目中我们将发送报文的时间戳放入数据字段,这样当接收到该报文应答的时候可以取出发送时间戳,将接收应答的时间戳减去发送时间戳就是报文往返时间(rtt)。提前预告一下,这里使用gettimeofday()API函数获取时间戳,详细介绍会在函数介绍部分说明。

ICMP 报文 C 语言实现可以用下面的数据结构表示:

struct icmp{
    unsigned char   type;         // 类型
    unsigned char   code;         // 代码
        unsigned short  checksum;     // 校验和
        unsigned short  id;            // 标识符
        unsigned short  sequence;     // 序号
        struct timeval  timestamp;    // 时间戳 
};

unsigned char 正好一字节,也就是 8bit,unsigned short 二字节,也就是 16bit,unsigned int4 字节(32bit),不过上面没用到。其中 struct timeval 类型可能有人不清楚,不过没关系,函数部分说明。

系统发送ICMP报文时会将ICMP报文作为IP的数据,也就是放入IP报文格式的数据字段,IP报文格式如下图所示:


注意上面4位首部长度和16位总长度,4位首部长度不包括数据字段,并且单位是4字节。16位总长度包括数据字段,单位是1字节。

IP报文首部C语言实现可以用下面的数据结构表示:

struct ip{
    unsigned char version:4;       // 版本
    unsigned char hlen:4;        // 首部长度
    unsigned char tos;             // 服务类型
    unsigned short len;         // 总长度
    unsigned short id;            // 标识符
    unsigned short offset;        // 标志和片偏移
    unsigned char ttl;            // 生存时间
    unsigned char protocol;     // 协议
    unsigned short checksum;    // 校验和
    struct in_addr ipsrc;        // 32位源ip地址
    struct in_addr ipdst;       // 32位目的ip地址
};

struct in_addr类型会函数介绍部分说明。

注意ICMP协议是IP层的一个协议,这里有人可能不清楚为什么ICMP协议是IP层的。

这是因为ICMP报文在发送给报文接收方时可能要经过若干子网,会牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送,是IP层的。

二、地址信息表示

当我们编写网络应用程序时,必然要使用地址信息指定数据传输给网络上哪个主机,那么地址信息应该包含哪些呢?

1.地址族,基于IPv4的地址族还是IPv6的地址族。

2.IP地址。

3.端口号。

为了便于记录地址信息,系统定义了如下结构体:

struct sockaddr_in{
    sa_family_t        sin_family;     // 地址族
    uint16_t        sin_port;        // 端口号
    struct in_addr  sin_addr;          // 32位IP地址
    char             sin_zero[8];    // 不使用
};

其中

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值