第 13 章 原始套接字与数据链
路访问编程
IPv4 数据报格式
几点说明
几点说明:首部长度是以 32 位(即 4 字节)为单位; 16 位的标
识用于分片和重组; DF 位(不分片); MF (还有片段);协议字段
表示封装在 IP 报文中的上层协议,典型的有: ICMP ( 1 )、 IGMP
( 2 )、 TCP ( 6 )、 UDP ( 17 );头部校验和只对 IP 头部(包括
选项)计算,校验算法是标准的因特网校验和算法,即简单的 16 位反
码求和。
版本 总长度(字节长度)
标识 片段偏移
首部长度 服务类型
0
D
F
M
F
存活时间( TTL ) 头部校验和协议
32 位源地址
32 位目的地址
选项(如果有的话)
数据
首部
数据
0 3 7
15
31
IP 数据报分片例子
IP 数据报是指指 I P 层端到端的传输单元(在分片
之前和重新组装之后),分组是指在 I P 层和链路
层之间传送的数据单元。
需要重申的是,任何传输层首部只出现在第 1 片数
据中。
原始套接字(概述)
原始套接字提供了一些使用 tcp 和 udp 协议不能实
现的功能,如:
使用原始套接字可以读/写 ICMPv4 、 IGMPv4 分组。如
Ping 程序, mroute 程序等;
使用原始套接字可以读/些特殊的 IPv4 数据包,内核不
处理这些数据报的 IPv4 协议字段。如大多数内核只处理 I
CMP 、 IGMP 、 TCP 、 UDP 的数据报。但协议字段还可
以为其他值,如 OSPF 直接使用 IP 协议,将 IP 数据报的
协议字段设为 89 ,此时,就必须有专门的程序通过原始
套接字来处理它们;
利用原始套接字还可以创建自定义的 IP 数据报首部,编
写基于 IP 协议的高层网络协议。
原始套接字创建
#include <sys/socket.h>
#include <netinet/in.h>
int socket(AF_INET, SOCK_RAW, int protocol);
protocol 参数一般不能为 0 ,如: IPPROTO_ICMP 。另外,只有超级用
户才能创建原始套接字。
用户可以通过设置 IP_HDRINCL 选项来编写自己的 IP 数据报首部:
const int on = 1;
setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
可以调用 bind 函数绑定原始套接字的本地 IP 地址,此时,所有输出的
数据报将用到源 IP 地址(仅当 IP_HDRINCL 未设置时);如果不调用 bi
nd 函数,由内核将源 IP 地址设成外出接口的主 IP 地址;
可以调用 connect 函数设置数据报的目的地址(注意并不需要真正的连
接)。此后,可直接调用 write 或 send 。
注意: bind 和 connect 时,端口已经没有意义了。