《网络编程》原始套接字 ---ping程序实现

概述

        基于字节流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)不可以访问传输层协议,只是对应用层的报文进行操作,传输层的数据报格式都是由系统提供的协议栈实现,用户只需要填充相应的应用层报文,由系统完成底层报文首部的填充并发送。原始套接字(SOCK_RAW)可以访问位于基层的传输层协议,原始套接字没有端口号。

        原始套接字(SOCK_RAW)是一种不同于 SOCK_STREAM、SOCK_DGRAM 的套接字,它实现于系统核心。原始套接字使进程可以读与写 ICMP、IGMP 等网络报文;也可以处理特殊的 IPv4 报文;进程还可以通过设置 IP_HDRINCL 套接字选项由用户自行构造 IP 首部。原始套接字可以用来自行组装 IP 数据报,然后将数据报发送到其他终端。但是只有管理员权限才能使用原始套接字,可防止普通用户往网络写入它们自行构造的 IP 数据报。

原始套接字创建

调用 socket 函数创建套接字时,指定套接字类型为 SOCK_RAW 以创建一个原始套接字。

int sockfd;
/* 创建一个 IPv4 的原始套接字 */
sockfd = socket(AF_INET, SOCK_RAW, protocol);

创建原始套接字之后,可以选择是否开启 IP_HDRINCL 套接字选项。

const int on = 1;
if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0)
/* 接下来是一些错误处理程序 */

原始套接字输出

原始套接字的输出遵循以下规则:

  1. 若套接字已经连接,则可以调用 write、writev 或 send 函数输出,否则,普通输出只能调用 sendto 或 sendmsg 函数并指定目的 IP 地址完成输出;
  2. 进程让内核所发送数据的起始地址:
    • 没有开启 P_HDRINCL 套接字选项,则起始地址是 IP 首部之后的第一个字节,因为此时,IP 首部由内核构造,并把它放在来自进程的数据之前;
    • 开启 P_HDRINCL 套接字选项,则起始地址是 IP 首部的第一个字节,因为此时,IP 首部由进程构造,所以进程数据包含 IP 首部;
  3. 内核会对超出外出接口 MTU(最大传输单元)的原始分组进行分片;

原始套接字输入

原始套接字遵循以下规则:

  1. 接收到的 UDP 分组和 TCP 分组绝不传递到任何原始套接字;
  2. 大多数的 ICMP 分组在内核处理完其中的 ICMP 消息后传递到原始套接字;
  3. 所有的 IGMP 分组在内核处理完其中的 IGMP 消息后传递到原始套接字;
  4. 内核无法识别的协议字段的所有 IP 数据报传递到原始套接字;
  5. 在数据报的所有分片到达之前,不传递任何分片到原始套接字;

         内核在传递 IP 数据报到原始套接字之前,必须对所有进程上的所有原始套接字进行匹配检测,若匹配成功,才把 IP 数据报的副本传递到匹配的原始套接字。检测匹配步骤如下:

  1. 创建原始套接字时 socket 函数的第三个参数必须指定非 0 值;
  2. 若原始套接字 bind 绑定到某个本地 IP 地址,则该本地 IP 地址必须与 IP 数据报的目的 IP 地址匹配;
  3. 若原始套接字已由 connect 调用指定某个外地 IP 地址,则该外地 IP 地址必须与 IP 数据报的源 IP 地址匹配;

Ping 程序

        ping 程序的操作比较简单,当源主机向目标主机发送了 ICMP 回显请求数据报后,它期待着目标主机的回答。目标主机在收到一个 ICMP 回显请求数据报后,它会交换源、目的主机的地址,然后将收到的 ICMP 回显请求数据报中的数据部分原封不动地封装在自己的 ICMP 回显应答数据报中,然后发回给发送 ICMP 回显请求的一方。如果校验正确,发送者便认为目标主机的回显服务正常,也即物理连接畅通。

        ping 程序编程需要用到 ICMP 协议,有关 ICMP 协议的知识可以参考前面的文章《ICMP 协议》。ping 命令只使用众多 ICMP 报文中的两种:"请求(ICMP_ECHO)"和"回应(ICMP_ECHOREPLY)",这两种 ICMP 报文格式如下图所示:


首先看下系统自带 ping 程序的输出:

$ ping www.github.com
PING github.com (192.30.252.128) 56(84) bytes of data.
64 bytes from github.com (192.30.252.128): icmp_req=1 ttl=45 time=269 ms
64 bytes from github.com (192.30.252.128): icmp_req=2 ttl=45 time=274 ms
64 bytes from github.com (192.30.252.12
  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值