logo资料库

TCP-IP详解卷2:实现.pdf

第1页 / 共887页
第2页 / 共887页
第3页 / 共887页
第4页 / 共887页
第5页 / 共887页
第6页 / 共887页
第7页 / 共887页
第8页 / 共887页
资料共887页,剩余部分请下载后查看
第1 章概述
1.1 引言
1.2 源代码表示
1.2.1 将拥塞窗口设置为1
1.2.2 印刷约定
1.3 历史
1.4 应用编程接口
1.5 程序示例
1.6 系统调用和库函数
1.7 网络实现概述
1.8 描述符
1.9 mbuf 与输出处理
1.9.1 包含插口地址结构的m b u f
1.9.2 包含数据的m b u f
1.9.3 添加I P 和U D P 首部
1.9.4 IP 输出
1.9.5 以太网输出
1.9.6 UDP 输出小结
1.10 输入处理
1.10.1 以太网输入
1.10.2 IP 输入
1.10.3 UDP 输入
1.10.4 进程输入
1 . 11 网络实现概述(续)
1.12 中断级别与并发
1.13 源代码组织
1.14 测试网络
1.15 小结
第2 章mbuf :存储器缓存
2.1 引言
2.2 代码介绍
2.2.1 全局变量
2.2.2 统计
2.2.3 内核统计
2.3 mbuf 的定义
2.4 m b u f 结构
2.5 简单的m b u f 宏和函数
2.5.1 m _ g e t 函数
2.5.2 M G E T 宏
2.5.3 m _ r e t r y 函数
2.5.4 mbuf 锁
2.6 m _ d e v g e t 和m _ p u l l u p 函数
2.6.1 m _ d e v g e t 函数
2.6.2 m t o d 和d t o m 宏
2.6.3 m _ p u l l u p 函数和连续的协议首部
2.6.4 m _ p u l l u p 和I P 的分片与重组
2.6.5 T C P 重组避免调用m _ p u l l u p
2.6.6 m _ p u l l u p 使用总结
2.7 mbuf 宏和函数的小结
2.8 Net/3 联网数据结构小结
2.9 m _ c o p y 和簇引用计数
2.10 其他选择
2 . 11 小结
第3 章接口层
3.1 引言
3.2 代码介绍
3.2.1 全局变量
3.2.2 SNMP 变量
3.3 i f n e t 结构
3.4 i f a d d r 结构
3.5 s o c k a d d r 结构
3.6 i f n e t 与i f a d d r 的专用化
3.7 网络初始化概述
3.8 以太网初始化
3.9 SLIP 初始化
3.10 环回初始化
3 . 11 i f _ a t t a c h 函数
3.12 i f i n i t 函数
3.13 小结
第4 章接口:以太网
4.1 引言
4.2 代码介绍
4.2.1 全局变量
4.2.2 统计量
4.2.3 SNMP 变量
4.3 以太网接口
4.3.1 l e i n t r 函数
4.3.2 l e r e a d 函数
4.3.3 e t h e r _ i n p u t 函数
4.3.4 e t h e r _ o u t p u t 函数
4.3.5 l e s t a r t 函数
4.4 i o c t l 系统调用
4.4.1 i f i o c t l 函数
4.4.2 i f c o n f 函数
4.4.3 举例
4.4.4 通用接口i o c t l 命令
4.4.5 i f _ d o w n 和i f _ u p 函数
4.4.6 以太网、S L I P 和环回
4.5 小结
第5 章接口:SLIP 和环回
5.1 引言
5.2 代码介绍
5.2.1 全局变量
5.2.2 统计量
5.3 SLIP 接口
5.3.1 SLIP 线路规程:S L I P D I S C
5.3.2 SLIP 初始化:s l o p e n 和s l i£┤䜃㯢㹦
5.3.3 SLIP 输入处理:s l i n p u t
5.3.4 SLIP 输出处理:s l o u t p u t
5.3.5 s l s t a r t 函数
5.3.6 SLIP 分组丢失
5.3.7 SLIP 性能考虑
5.3.8 s l c l o s e 函数
5.3.9 s l t i o c t l 函数
5.4 环回接口
5.5 小结
第6 章IP 编址
6.1 引言
6.1.1 IP 地址
6.1.2 IP 地址的印刷规定
6.1.3 主机和路由器
6.2 代码介绍
6.3 接口和地址小结
6.4 s o c k a d d r _ i n 结构
6.5 i n _ i f a d d r 结构
6.6 地址指派
6.6.1 i f i o c t l 函数
6.6.2 i n _ c o n t r o l 函数
6.6.3 前提条件:S I O C S I F A D D R 、⎱뻏鴑曟භ徱╱᎒ᭀ兴䴻恲ǫ喒捾㖪ꚮ斌᲍랍ᙺ౐矪儡犢ꎚ郵锫篏䃍隸ጩ향飅夛즴헚羘함ਖ਼辯靋튶띔陬벌惓Ⳳ혎
6.6.4 地址指派:S I O C S I F A D D R
6.6.5 i n _ i f i n i t 函数
6.6.6 网络掩码指派:S I O C S I F N E T M A S K
6.6.7 目的地址指派:S I O C S I F D S T A D D R
6.6.8 获取接口信息
6.6.9 每个接口多个I P 地址
6.6.10 附加I P 地址:S I O C A I F A D D R
6 . 6 . 11 删除I P 地址:S I O C D I F A D D R
6.7 接口i o c t l 处理
6.7.1 l e i o c t l 函数
6.7.2 s l i o c t l 函数
6.7.3 l o i o c t l 函数
6.8 Internet 实用函数
6.9 i f n e t 实用函数
6.10 小结
第7 章域和协议
7.1 引言
7.2 代码介绍
7.2.1 全局变量
7.2.2 统计量
7.3 d o m a i n 结构
7.4 p r o t o s w 结构
7.5 IP 的d o m a i n 和p r o t o s w 结构
7.6 p f f i n d p r o t o 和p f f i n d t y p e 函数
7.7 p f c t l i n p u t 函数
7.8 IP 初始化
7.8.1 Internet 传输分用
7.8.2 i p _ i n i t 函数
7.9 s y s c t l 系统调用
7.10 小结
第8 章IP :网际协议
8.1 引言
8.2 代码介绍
8.2.1 全局变量
8.2.2 统计量
8.2.3 SNMP 变量
8.3 IP 分组
8.4 输入处理:ip intr 函数
8.4.1 ip intr 概观
8.4.2 验证
8.4.3 转发或不转发
8.4.4 重装和分用
8.5 转发:i p _ f o r w a r d 函数
8.6 输出处理:i P _ o u t p u t 函数
8.6.1 首部初始化
8.6.2 路由选择
8.6.3 源地址选择和分片
8.7 Internet 检验和:i n _ c k s u m 函数
8.8 s e t s o c k o p t 和g e t s o c k o p t 系统调用
8.8.1 P R C O _ S E T O P T 的处理
8.8.2 P R C O _ G E T O P T 的处理
8.9 i p _ s y s c t l 函数
8.10 小结
第9 章IP 选项处理
9.1 引言
9.2 代码介绍
9.2.1 全局变量
9.2.2 统计量
9.3 选项格式
9.4 i p _ d o o p t i o n s 函数
9.5 记录路由选项
9.6 源站和记录路由选项
9.6.1 s a v e _ r t e 函数
9.6.2 i p _ s r c r o u t e 函数
9.7 时间戳选项
9.8 i p _ i n s e r t o p t i o n s 函数
9.9 i p _ p c b o p t s 函数
9.10 一些限制
9 . 11 小结
第10 章IP 的分片与重装
10.1 引言
10.2 代码介绍
10.2.1 全局变量
10.2.2 统计量
10.3 分片
10.4 i p _ o p t c o p y 函数
10.5 重装
10.6 ip_reass 函数
10.7 i p _ s l o w t i m o 函数
10.8 小结
第11 章ICMP :Internet 控制报文协议
11.1 引言
11.2 代码介绍
11.2.1 全局变量
11.2.2 统计量
11.2.3 SNMP 变量
11.3 i c m p 结构
11.4 ICMP 的pro tosw 结构
11.5 输入处理:i c m p _ i n p u t 函数
11.6 差错处理
11.7 请求处理
11.7.1 回显询问:I C M P _ E C H O 和I C M P _ E C H O R E P L Y
11.7.2 时间戳询问:I C M P _ T S T A M P 和I C M P _ T S T A M P R E P L Y
11.7.3 地址掩码询问:I C M P _ M A S K R E Q 和I C M P _ M A S K R E P L Y
11.7.4 信息询问:I C M P _ I R E Q 和I C M P _ I R E Q R E P L Y
11.7.5 路由器发现:I C M P _ R O U T E R A D V E R T 和I C M P _ R O U T E R S O L I C I T
11.8 重定向处理
11.9 回答处理
11.10 输出处理
11 . 11 i c m p _ e r r o r 函数
11.12 i c m p _ r e f l e c t 函数
11.13 i c m p _ s e n d 函数
11.14 i c m p _ s y s c t l 函数
11.15 小结
第12 章IP 多播
12.1 引言
12.2 代码介绍
12.2.1 全局变量
12.2.2 统计量
12.3 以太网多播地址
12.4 e t h e r _ m u l t i 结构
12.5 以太网多播接收
12.6 i n _ m u l t i 结构
12.7 i p _ m o p t i o n s 结构
12.8 多播的插口选项
12.9 多播的T T L 值
12.9.1 MBONE
12.9.2 扩展环搜索
12.10 i p _ s e t m o p t i o n s 函数
12.10.1 选择一个明确的多播接口:I P _ M U L ၭ羍龡璍⣒涱柽覗ꀏ乎ꓵ�徇
12.10.2 选择明确的多播T T L :I P _ M U L T媛鼔苎縏鑟鄁宷ﲅ�鲞敶ﮝᕟ
12.10.3 选择多播环回:I P _ M U L T I C A S T _ L O O P
1 2 . 11 加入一个I P 多播组
1 2 . 11.1 i n _ a d d m u l t i 函数
1 2 . 11.2 s l i o c t l 和l o i o c t l 函数:S I O C A D D M U L T I 和S I O C D E L M U L T I
1 2 . 11.3 l e i o c t l 函数:S I O C A D D M U L T I 和S I O C D E L M U L T I
1 2 . 11.4 e t h e r _ a d d m u l t i 函数
12.12 离开一个I P 多播组
12.12.1 i n _ d e l m u l t i 函数
12.12.2 e t h e r _ d e l m u l t i 函数
12.13 i p _ g e t m o p t i o n s 函数
12.14 多播输入处理:i p i n t r 函数
12.15 多播输出处理:i p _ o u t p u t 函数
12.16 性能的考虑
12.17 小结
第13 章IGMP :Internet 组管理协议
13.1 引言
13.2 代码介绍
13.2.1 全局变量
13.2.2 统计量
13.2.3 SNMP 变量
13.3 i g m p 结构
13.4 IGMP 的p r o t o s w 的结构
13.5 加入一个组:i g m p _ j o i n g r o u p 函数
13.6 i g m p _ f a s t t i m o 函数
13.7 输入处理:i g m p _ i n p u t 函数
13.7.1 成员关系查询:I G M P _ H O S T _ M E M B E R S H I P _ Q U E R Y
13.7.2 成员关系报告:I G M P _ H O S T _ M E M B E R S H I P _ R E P O R T
13.8 离开一个组:i g m p _ l e a v e g r o u p 函数
13.9 小结
第14 章IP 多播选路
14.1 引言
14.2 代码介绍
14.2.1 全局变量
14.2.2 统计量
14.2.3 SNMP 变量
14.3 多播输出处理(续)
14.4 m r o u t e d 守护程序
14.5 虚拟接口
14.5.1 虚拟接口表
14.5.2 a d d _ v i f 函数
14.5.3 d e l _ v i f 函数
14.6 IGMP(续)
14.6.1 a d d _ l g r p 函数
14.6.2 d e l _ l g r p 函数
14.6.3 g r p l s t _ m e m b e r 函数
14.7 多播选路
14.7.1 多播选路表
14.7.2 d e l _ m r t 函数
14.7.3 a d d _ m r t 函数
14.7.4 m r t f i n d 函数
14.8 多播转发:i p _ m f o r w a r d 函数
14.8.1 p h y i n t _ s e n d 函数
14.8.2 t u n n e l _ s e n d 函数
14.9 清理:i p _ m r o u t e r _ d o n蚅턞슸⦑
14.10 小结
第15 章插口层
15.1 引言
15.2 代码介绍
15.3 s o c k e t 结构
15.4 系统调用
15.4.1 举例
15.4.2 系统调用小结
15.5 进程、描述符和插口
15.6 s o c k e t 系统调用
15.6.1 s o c r e a t e 函数
15.6.2 超级用户特权
15.7 g e t s o c k 和s o c k a r g s 函数
15.8 b i n d 系统调用
15.9 l i s t e n 系统调用
15.10 t s l e e p 和w a k e u p 函数
1 5 . 11 a c c e p t 系统调用
15.12 s o n e w c o n n 和s o i s c o n n e c t e d 函数
15.13 c o n n e c t 系统调用
15.13.1 s o c o n n e c t 函数
15.13.2 切断无连接插口和外部地址的关联
15.14 s h u t d o w n 系统调用
15.15 c l o s e 系统调用
15.15.1 s o o _ c l o s e 函数
15.15.2 s o c l o s e 函数
15.16 小结
第16 章插口I/O
16.1 引言
16.2 代码介绍
16.3 插口缓存
16.4 w r i t e 、w r i t e v 、s e n d t o 和s e n d m s g 系统调用
16.4 w r i t e 、w r i t e v 、s e n d t o 和s e n d m s g 系统调用
16.5 s e n d m s g 系统调用
16.6 s e n d i t 函数
16.6.1 u i o m o v e 函数
16.6.2 举例
16.6.3 s e n d i t 代码
16.7 s o s e n d 函数
16.7.1 可靠的协议缓存
16.7.2 不可靠的协议缓存
16.7.3 s o s e n d 函数小结
16.7.4 性能问题
16.8 r e a d 、r e a d v 、r e c v f r o m 和r e c v m s g 系统调用
16.9 r e c v m s g 系统调用
16.10 r e c v i t 函数
1 6 . 11 s o r e c e i v e 函数
1 6 . 11.1 带外数据
1 6 . 11.2 举例
1 6 . 11.3 其他的接收操作选项
1 6 . 11.4 接收缓存的组织:报文边界
1 6 . 11.5 接收缓存的组织:没有报文边界
1 6 . 11.6 控制信息和带外数据
16.12 s o r e c e i v e 代码
16.13 s e l e c t 系统调用
16.13.1 s e l s c a n 函数
16.13.2 s o o _ s e l e c t 函数
16.13.3 s e l r e c o r d 函数
16.13.4 s e l w a k e u p 函数
16.14 小结
第17 章插口选项
17.1 引言
17.2 代码介绍
17.3 s e t s o c k o p t 系统调用
17.4 g e t s o c k o p t 系统调用
17.5 f c n t l 和i o c t l 系统调用
17.5.1 f c n t l 代码
17.5.2 i o c t l 代码
17.6 g e t s o c k n a m e 系统调用
17.7 g e t p e e r n a m e 系统调用
17.8 小结
第18 章Radix 树路由表
18.1 引言
18.2 路由表结构
18.3 选路插口
18.4 代码介绍
18.4.1 全局变量
18.4.2 统计量
18.4.3 SNMP 变量
18.5 Radix 结点数据结构
18.6 选路结构
18.7 初始化:r o u t e _ i n i t 和r t a b l e _ i n i t 函数
18.8 初始化:r n _ i n i t 和r n _ i n i t h e a d 函数
18.9 重复键和掩码列表
18.10 r n _ m a t c h 函数
1 8 . 11 r n _ s e a r c h 函数
18.12 小结
第19 章选路请求和选路消息
19.1 引言
1 9 . 2 r t a l l o c 和r t a l l o 䓩肿鏗憼
19.3 宏R T F R E E 和r t f r e e 函数
19.4 r t r e q u e s t 函数
19.5 r t _ s e t g a t e 函数
19.6 r t i n i t 函数
19.7 r t r e d i r e c t 函数
19.8 选路消息的结构
19.9 r t _ m i s s m s g 函数
19.10 r t _ i f m s g 函数
1 9 . 11 r t _ n e w a d d r m s g 函数
19.12 r t _ m s g 1 函数
19.13 r t _ m s g 2 函数
19.14 s y s c t l _ r t a b l e 函数
19.15 s y s c t l _ d u m p e n t r y 函数
19.16 s y s c t l _ i f l i s t 函数
19.17 小结
第20 章选路插口
20.1 引言
20.2 r o u t e d o m a i n 和p r o t o s w 结构
20.3 选路控制块
20.4 r a w _ i n i t 函数
20.5 r o u t e _ o u t p u t 函数
20.6 r t _ x a d d r s 函数
20.7 r t _ s e t m e t r i c s 函数
20.8 r a w _ i n p u t 函数
20.9 r o u t e _ u s r r e q 函数
20.10 r a w _ u s r r e q 函数
2 0 . 11 r a w _ a t t a c h 、r a w _ d e t a c h 和r a w _ d i s c o n n e c t 函数
20.12 小结
第21 章ARP :地址解析协议
21.1 介绍
21.2 ARP 和路由表
21.3 代码介绍
21.3.1 全局变量
21.3.2 统计量
21.3.3 SNMP 变量
21.4 ARP 结构
21.5 a r p w h o h a s 函数
21.6 a r p r e q u e s t 函数
21.7 a r p i n t r 函数
21.8 i n _ a r p i n p u t 函数
21.9 A R P 定时器函数
21.9.1 a r p t i m e r 函数
21.9.2 a r p t f r e e 函数
21.10 a r p r e s o l v e 函数
2 1 . 11 a r p l o o k u p 函数
21.12 代理A R P
21.13 a r p _ r t r e q u e s t 函数
21.14 ARP 和多播
21.15 小结
第22 章协议控制块
22.1 引言
22.2 代码介绍
22.2.1 全局变量
22.2.2 统计量
22.3 i n p c b 的结构
22.4 i n _ p c b a l l o c 和i n _ p c b d e t a c h 函数
22.5 绑定、连接和分用
22.6 i n _ p c b l o o k u p 函数
22.7 i n _ p c b b i n d 函数
22.8 i n _ p c b c o n n e c t 函数
22.9 i n _ p c b d i s c o n n e c t 函数
22.10 i n _ s e t s o c k a d d r 哵᠀걺쳭傢ࠪ䩘ꄡ憕଍㬿꫱蕇㤷ᴃ㵳䎁꾵ﴞ勃筏钖ݡ뛁몈
2 2 . 11 i n _ p c b n o t i f y 、i n _ r t c h a n g e 和i n _ l o s i n g 函数
2 2 . 11.1 i n _ r t c h a n g e 函数
2 2 . 11.2 重定向和原始插口
2 2 . 11.3 ICMP 差错和U D P 插口
2 2 . 11.4 i n _ l o s i n g 函数
22.12 实现求精
22.13 小结
第23 章UDP :用户数据报协议
23.1 引言
23.2 代码介绍
23.2.1 全局变量
23.2.2 统计量
23.2.3 SNMP 变量
23.3 UDP 的p r o t o s w 结构
23.4 UDP 的首部
23.5 u d p _ i n i t 函数
23.6 u d p _ o u t p u t 函数
23.6.1 在前面加上I P / U D P 首部和m b u f 簇
23.6.2 UDP 检验和计算和伪首部
23.7 u d p _ i n p u t 函数
23.7.1 对收到的U D P 数据报的一般确认
23.7.2 分用单播数据报
23.7.3 分用多播和广播数据报
23.7.4 连接上的U D P 插口和多接口主机
23.8 u d p _ s a v e o p t 函数
23.9 u d p _ c t l i n p u t 函数
23.10 u d p _ u s r r e q 函数
2 3 . 11 u d p _ s y s c t l 函数
23.12 实现求精
23.12.1 UDP PCB 高速缓存
23.12.2 UDP 检验和
23.13 小结
第24 章TCP :传输控制协议
24.1 引言
24.2 代码介绍
24.2.1 全局变量
24.2.2 统计量
24.2.3 SNMP 变量
24.3 TCP 的p r o t o s w 结构
24.4 TCP 的首部
24.5 TCP 的控制块
24.6 TCP 的状态变迁图
24.7 TCP 的序号
24.8 t c p _ i n i t 函数
24.9 小结
第25 章TCP 的定时器
25.1 引言
25.2 代码介绍
25.3 t c p _ c a n c e l t i m e r©馰�뤫
25.4 t c p _ f a s t t i m o 函数
25.5 t c p _ s l o w t i m o 函数
25.6 t c p _ t i m e r s 函数
25.6.1 FIN_WA I T _ 2 和2 M S L 定时器
25.6.2 持续定时器
25.6.3 连接建立定时器和保活定时器
25.7 重传定时器的计算
25.8 t c p _ n e w t c p c b 算法
25.9 t c p _ s e t p e r s i s t 函数
25.10 t c p _ x m i t _ t i m e r 儬
2 5 . 11 重传超时:t c p _ t i m e r s 函数
2 5 . 11.1 慢起动和避免拥塞
2 5 . 11.2 精确性
25.12 一个RT T 的例子
25.13 小结
第26 章TCP 输出
26.1 引言
26.2 t c p _ o u t p u t 概述
26.3 决定是否应发送一个报文段
26.4 TCP 选项
26.5 窗口大小选项
26.6 时间戳选项
26.6.1 哪个时间戳需要回显,RFC 1323 算法
26.6.2 哪个时间戳需要回显,正确的算法
26.6.3 时间戳与延迟A C K
26.7 发送一个报文段
26.8 t c p _ t e m p l a t e 函数
26.9 t c p _ r e s p o n d 函数
26.10 小结
第27 章TCP 的函数
27.1 引言
27.2 t c p _ d r a i n 函数
27.3 t c p _ d r o p 函数
27.4 t c p _ c l o s e 函数
27.4.1 路由特性
27.4.2 资源释放
27.5 tcp_mss 函数
27.6 t c p _ c t l i n p u t 函数
27.7 tcp_notify 函数
27.8 tcp_quench 函数
27.9 T C P _ R E A S S 宏和t c p _ r e a s s 函数
27.9.1 T C P _ R E A S S 宏
27.9.2 T C P _ R E A S S 函数
27.10 t c p _ t r a c e 函数
2 7 . 11 小结
第28 章TCP 的输入
28.1 引言
28.2 预处理
28.3 t c p _ d o o p t i o n s 函数
28.4 首部预测
28.5 TCP 输入:缓慢的执行路径
28.6 完成被动打开或主动打开
28.6.1 完成被动打开
28.6.2 完成主动打开
28.7 PAW S :防止序号回绕
28.8 裁剪报文段使数据在窗口内
28.9 自连接和同时打开
28.10 记录时间戳
2 8 . 11 RST 处理
28.12 小结
第29 章TCP 的输入(续)
29.1 引言
29.2 ACK 处理概述
29.3 完成被动打开和同时打开
29.4 快速重传和快速恢复的算法
29.5 ACK 处理
29.6 更新窗口信息
29.7 紧急方式处理
29.8 t c p _ p u l l o u t o f b a n d 函数
29.9 处理已接收的数据
29.10 FIN 处理
2 9 . 11 最后的处理
29.12 实现求精
29.13 首部压缩
29.13.1 引言
29.13.2 首部字段的压缩
29.13.3 特殊情况
29.13.4 实例
29.13.5 配置
29.14 小结
第30 章TCP 的用户需求
30.1 引言
30.2 t c p _ u s r r e q 函数
30.3 t c p _ a t t a c h 函数
30.4 t c p _ d i s c o n n e c t 函数
30.5 t c p _ u s r c l o s e d 函数
30.6 t c p _ c t l o u t p u t 函数
30.7 小结
第31 章BPF :BSD 分组过滤程序
31.1 引言
31.2 代码介绍
31.2.1 全局变量
31.2.2 统计量
31.3 b p f _ i f 结构
31.4 b p f _ d 结构
31.4.1 b p f o p e n 函数
31.4.2 b p f i o c t l 函数
31.4.3 b p f _ s e t i f 函数
31.4.4 b p f _ a t t a c h d 函数
31.5 BPF 的输入
31.5.1 b p f _ t a p 函数
31.5.2 c a t c h p a c k e t 函数
31.5.3 b p f r e a d 函数
31.6 BPF 的输出
31.7 小结
第32 章原始IP
32.1 引言
32.2 代码介绍
32.2.1 全局变量
32.2.2 统计量
32.3 原始I P 的p r o t o s w 结构
32.4 r i p _ i n i t 函数
32.5 r i p _ i n p u t 函数
32.6 r i p _ o u t p u t 函数
32.7 r i p _ u s r r e q 函数
32.8 r i p _ c t l o u t p u t 函数
32.9 小结
附录A 部分习题的解答
第1 章
第2 章
第3 章
第4 章
第5 章
第6 章
第7 章
第8 章
第9 章
第1 0 章
第11 章
第1 2 章
第1 3 章
第1 4 章
第1 5 章
第1 6 章
第1 7 章
第1 8 章
第1 9 章
第2 0 章
第2 1 章
第2 2 章
第2 3 章
第2 4 章
第2 5 章
第2 6 章
第2 7 章
第2 8 章
第2 9 章
第3 0 章
第3 1 章
第3 2 章
附录B 源代码的获取
第1章 概 述 1.1 引言 本章介绍伯克利 ( B e r k e l e y )联网程序代码。开始我们先看一段源代码并介绍一些通篇要用 的印刷约定。对各种不同代码版本的简单历史回顾让我们可以看到本书中的源代码处于什么 位置。接下来介绍了两种主要的编程接口,它们在 U n i x与非U n i x系统中用于编写T C P / I P协议。 然后我们介绍一个简单的用户程序,它发送一个 U D P数据报给一个位于另一主机上的日 期/时间服务器,服务器返回一个 U D P数据报,其中包含服务器上日期和时间的 A S C I I码字符 串。这个进程发送的数据报经过所有的协议栈到达设备驱动器,来自服务器的应答从下向上 经过所有协议栈到达这个进程。通过这个例子的这些细节介绍了很多核心数据结构和概念, 这些数据结构和概念在后面的章节中还要详细说明。 本章的最后介绍了在本书中各源代码的组织,并显示了联网代码在整个组织中的位置。 1.2 源代码表示 不考虑主题,列举 15 000 行源代码本身就是一件难事。下面是所有源代码都使用的文本 格式: 1.2.1 将拥塞窗口设置为 1 3 8 7 - 3 8 8 这是文件t c p _ s u b r . c中的函数t c p _ q u e n c h。这些源文件名引用 4 . 4 B S D - L i t e发 布的文件。 4 . 4 B S D在1 . 1 3节中讨论。每个非空白行都有编号。正文所描述的代码的起始和结 束位置的行号记于行开始处,如本段所示。有时在段前有一个简短的描述性题头,对所描述 的代码提供一个概述。 这些源代码同 4 . 4 B S D - L i t e发行版一样,偶尔也包含一些错误,在遇到时我们会提出来并 加以讨论,偶尔还包括一些原作者的编者评论。这些代码已通过了 G N U缩进程序的运行,使 它们从版面上看起来具有一致性。制表符的位置被设置成 4个栏的界线使得这些行在一个页面 中显示得很合适。在定义常量时,有些 # i f d e f语句和它们的对应语句 # e n d i f被删去 (如: G A T E W A Y和M R O U T I N G,因为我们假设系统被作为一个路由器或多播路由器 )。所有r e g i s t e r说 bbs.theithome.com Linux公社 www.linuxidc.com
欢迎点击这里的链接进入精彩的Linux公社 网站 Linux公社(www.Linuxidc.com)于2006年9月25日注册并开通网 站,Linux现在已经成为一种广受关注和支持的一种操作系统, IDC是互联网数据中心,LinuxIDC就是关于Linux的数据中心。 Linux公社是专业的Linux系统门户网站,实时发布最新Linux资 讯,包括Linux、Ubuntu、Fedora、RedHat、红旗Linux、Linux教 程、Linux认证、SUSE Linux、Android、Oracle、Hadoop、 CentOS、MySQL、Apache、Nginx、Tomcat、Python、Java、C语 言、OpenStack、集群等技术。 Linux公社(LinuxIDC.com)设置了有一定影响力的Linux专题栏 目。 Linux公社 主站网址:www.linuxidc.com 旗下网站: www.linuxidc.net 包括:Ubuntu 专题 Fedora 专题 Android 专题 Oracle 专题 Hadoop 专题 RedHat 专题 SUSE 专题 红旗 Linux 专题 CentOS 专题 Linux 公社微信公众号:linuxidc_com
2计计TCP/IP详解 卷 2:实现 明符被删去。有些地方加了一些注释,并且一些注释中的印刷错误被修改了,但代码的其他 部分被保留下来。 这些函数大小不一,从几行 (如前面的 t c p _ q u e n c h)到最大11 0 0行(t c p _ i n p u t)。超过 大约4 0行的函数一般被分成段,一段一段地显示。虽然尽量使代码和相应的描述文字放在同 一页或对开的两页上,但为了节约版面,不可能完全做到。 本书中有很多对其他函数的交叉引用。为了避免给每个引用都添加一个图号和页码,书 封底内页中有一个本书中描述的所有函数和宏的字母交叉引用表和描述的起始页码。因为本 书的源代码来自公开的 4 . 4 B S D _ L i t e版,因此很容易获得它的一个拷贝:附录 B详细说明了各 种方法。当你阅读文章时,有时它会帮助你搜索一个在线拷贝 [例如U n i x程序grep ( 1 )]。 描述一个源代码模块的各章通常以所讨论的源文件的列表开始,接着是全局变量、代码 维护的相关统计以及一个实际系统的一些例子统计,最后是与所描述协议相关的 S N M P变量。 全局变量的定义通常跨越各种源文件和头文件,因此我们将它们集中到的一个表中以便于参 考。这样显示所有的统计,简化了后面当统计更新时对代码的讨论。卷 1的第 2 5章提供了 S N M P的所有细节。我们在本文中关心的是由内核中的 T C P / I P例程维护的、支持在系统上运 行的S N M P代理的信息。 1.2.2 印刷约定 通篇的图中,我们使用一个等宽字体表示变量名和结构成员名 (m _ n e x t),用斜体等宽字 体表示定义常量 ( N U L L)或常量的值 (5 1 2)的名称,用带花括号的粗体等宽字体表示结构名称 (m b u f { })。这里有一个例子: 在表中,我们使用等宽字体表示变量名称和结构成员名称,用斜体等宽字体表示定义的 常量。这里有一个例子: m _ f l a g s 说 明 M _ B C A S T 以链路层广播发送 /接收 通常用这种方式显示所有的 # d e f i n e符号。如果必要,我们显示符号的值 (M _ B C A S T的 值无关紧要 )并且所列符号按字母排序,除非对顺序有特殊要求。 通篇我们会使用像这样的缩进的附加说明来描述历史的观点或实现的细节。 我们用有一个数字在圆括号里的命令名称来表示 U n i x命令,如 g r e p( 1 )。圆括号中的数字 是4 . 4 B S D手册“manual page”中此命令的节号,在那里可以找到其他的信息。 1.3 历史 本书讨论在伯克利的加利福尼亚大学计算机系统研究组的 T C P / I P实现的常用引用。历史 上,它曾以 4.x BSD系统(伯克利软件发行 )和“B S D联网版本”发行。这个源代码是很多其他 实现的起点,不论是 U n i x或非U n i x操作系统。 图1 - 1显示了各种 B S D版本的年表,包括重要的 T C P / I P特征。显示在左边的版本是公开可 www.linuxidc.com Linux公社 www.linuxidc.com
第1章 概 述计计3 用源代码版,它包括所有联网代码:协议本身、联网接口的内核例程及很多应用和实用程序 (如Te l n e t和F T P )。 4.2BSD (1983) 第一次被广泛应用的 TCP/IP版本 4.3BSD (1996) 改进了TCP性能 4.3BSD Tahoe (1988) 慢启动,防拥塞,快速 重传 4.3BSD Reno (1990) 快速恢复, T C P首部预 测,S L I P首部压缩,路 由表改变 4.4BSD(1993) 多播,长肥管道的修改 BSD联网软件 版本1.0(1989):Net/1 BSD联网软件 版本2.0(1991):Net/2 4.4BSD-Lite(1994) 在正文中用Net/3表示 图1-1 带有重要 T C P / I P特征的各种 B S D版本 虽然本文描述的软件的官方名称为 4 . 4 B S D - L i t e发行软件,但我们简单地称它为 N e t / 3。 虽然源代码由 U. C. Berkeley发行并被称为伯克利软件发行,但 T C P / I P代码确实是各种研 究者的工作的融合,包括伯克利和其他地区的研究人员。 通篇我们会使用术语源于伯克利的实现来谈及各厂商的实现,如 SunOS 4.x、系统V版本 4 ( S V R 4 )和AIX 3.2,它们的 T C P / I P代码最初都是从伯克利源代码发展而来的。这些实现有很 多共同之处,通常包括同样的错误! 在图1 - 1中没有显示的伯克利联网代码的第 1版实际上是1 9 8 2年的4 . 1 c B S D,但是 广泛发布的是1 9 8 3年的版本4 . 2 B S D。 在4 . 1 c B S D之前的 B S D版本使用的一个 T C P / I P实现,是由 Bolt Beranek and N e w m a n ( B B N )的Rob Gurwitz和Jack Haverty开发的。[Salus 1994]的第1 8章提供了另 外一些合并到 4 . 2 B S D中的B B N代码细节。其他对伯克利 T C P / I P代码有影响的实现是 由B a l l i s t i c s研究室的Mike Muuss为P D P - 11开发的T C P / I P实现。 描述联网代码从一个版本到下一个版本的变化的文档有限。 [Karels and McKusick 1986]描述了从 4 . 2 B S D到4 . 3 B S D的变化,并且 [Jacobson 1990d]描述了从 4.3BSD Ta h o e到4.3BSD Reno的变化。 1.4 应用编程接口 在互联网协议中两种常用的应用编程接口 ( A P I )是插口 ( s o c k e t )和T L I (运输层接口 )。前者 www.linuxidc.com Linux公社 www.linuxidc.com
4计计TCP/IP详解 卷 2:实现 有时称为伯克利插口 (Berkeley socket),因为它被广泛地发布于 4 . 2 B S D系统中(见图1 - 1 )。但它 已被移植到很多非 BSD Unix系统和很多非 U n i x系统中。后者最初是由 AT & T开发的,由于被 X / O p e n承认,有时叫作 X T I ( X / O p e n传输接口)。X / O p e n是一个计算机厂商的国际组织,它制 定自己的标准。X T I是T L I的一个有效超集。 虽然本文不是一本程序设计书,但既然在 N e t / 3 (和所有 B S D版本)中应用编程用插口来访 问T C P / I P,我们还是说明一下插口。在各种非 U n i x系统中也实现了插口。插口和 T L I的编程细 节在[Stevens 1990]中可以找到。 系统Ⅴ版本 4 ( S V R 4 )也为应用编程提供了一组插口 A P I,在实现上与本文中列举的有所不 同。在S V R 4中的插口基于“流”子系统,在 [Rago 1993]中有所说明。 1.5 程序示例 在本章我们用一个简单的 C程序(图1- 2 )来介绍一些 B S D网络实现的很多特点。 图1-2 程序示例:发送一个数据报给 U D P日期/时间服务器并读取一个应答 www.linuxidc.com Linux公社 www.linuxidc.com
第1章 概 述计计5 1. 创建一个数据报插口 1 9 - 2 0 s o c k e t函数创建了一个UDP 插口,并且给进程返回一个保存在变量 s o c k f d中的描 述符。差错处理函数 e r r _ s y s在[Stevens 1992]的附录 B . 2中给出。它接收任意数量的参数, 并用v s p r i n t f对它们格式化,将系统调用产生的 e r r n o值对应的 U n i x错误信息打印出来, 并中断进程。 我们在不同的地方使用术语插口: ( 1 )为4 . 2 B S D开发的程序用来访问网络协议的 A P I通常叫插口 A P I或者就叫插口接口; (2) socket是插口 A P I中的一个函数的名字; ( 3 )我们把调用 s o c k e t创建的端点叫做一个插口,如评注“创建一个数据报插口”。 但是这里还有一些地方也使用术语插口: (4) socket函数的返回值叫一个插口描 述符或者就叫一个插口; ( 5 )在内核中的伯克利联网协议实现叫插口实现,相比较其 他系统如:系统V的流实现。( 6 )一个I P地址和一个端口号的组合叫一个插口, I P地址 和端口号对叫一个插口对。所幸的是引用哪一种术语是很明显的。 2. 将服务器地址放到结构 s o c k a d d r _ i n中 2 1 - 2 4 在一个互联网插口地址结构中存放日期 /时间服务器的 I P地址( 1 4 0 . 2 5 2 . 1 . 3 2 )和端口号 ( 1 3 )。大多数 T C P / I P实现都提供标准的日期 /时间服务器,它的端口号为 13 [Stevens 1994,图 1- 9 ]。我们对服务器主机的选择是随意的—直接选择了提供此服务的本地主机 (图1- 1 7 )。 函数i n e t _ a d d r将一个点分十进制表示的 I P地址的 A S C I I字符串转换成网络字节序的 3 2 b i t二进制整数。 ( I n t e r n e t协议族的网络字节序是高字节在后 )。函数h t o n s把一个主机字节序 的短整数(可能是低字节在后 )转换成网络字节序 (高字节在后 )。在S p a r c这种系统中,整数是高 字节在后的格式, h t o n s 典型地是一个什么也不做的宏。但是在低字节在后的 8 0 3 8 6上的 B S D / 3 8 6系统中, h t o n s可能是一个宏或者是一个函数,来完成一个 16 bit整数中的两个字节 的交换。 3. 发送数据报给服务器 2 5 - 2 7 程序调用 s e n d t o发送一个 1 5 0字节的数据报给服务器。因为是运行时栈中分配的未初 始化数组,1 5 0字节的缓存内容是不确定的。但没有关系,因为服务器根本就不看它收到的报 文的内容。当服务器收到一个报文时,就发送一个应答给客户端。应答中包含服务器以可读 格式表示的当前时间和日期。 我们选择的 1 5 0字节的客户数据报是随意的。我们有意选择一个报文长度在 1 0 0 ~ 2 0 8之间 的值,来说明在本章的后面要提到的 m b u f链表的使用。为了避免拥塞,在以太网中,我们希 望长度要小于1 4 7 2。 4. 读取从服务器返回的数据报 2 8 - 3 2 程序通过调用 r e c v f r o m来读取从服务器发回的数据报。 U n i x服务器典型地发回一 个如下格式的2 6字节字符串 Sat Dec 11 11:28:05 1993\r\n \ r是一个 A S C I I回车符, \ n是A S C I I换行符。我们的程序将回车符替换成一个空字节,然后 调用p r i n t f输出结果。 在本章和下一章我们在分析函数 s o c k e t、s e n d t o和r e c v f r o m的实现时,要进入这个 例子的一些细节部分。 www.linuxidc.com Linux公社 www.linuxidc.com
6计计TCP/IP详解 卷 2:实现 1.6 系统调用和库函数 所有的操作系统都提供服务访问点,程序可以通过它们请求内核中的服务。各种 U n i x都 提供精心定义的有限个内核入口点,即系统调用。我们不能改变系统调用,除非我们有内核 的源代码。 U n i x第7版提供大约 5 0个系统调用, 4 . 4 B S D提供大约 1 3 5个,而 S V R 4大约有 1 2 0 个。 在《U n i x程序员手册》第 2节中有系统调用接口的文档。它是以 C语言定义的,在任何给 定的系统中无需考虑系统调用是如何被调用的。 在各种U n i x系统中,每个系统调用在标准 C函数库中都有一个相同名字的函数。一个应用 程序用标准C的调用序列来调用此函数。这个函数再调用相应的内核服务,所使用的技术依赖 于所在系统。例如,函数可能把一个或多个 C参数放到通用寄存器中,并执行几条机器指令产 生一个软件中断进入内核。对于我们来说,可以把系统调用看成 C函数。 在《U n i x程序员手册》的第 3节中为程序员定义了一般用途的函数。虽然这些函数可能调 用一个或多个内核系统调用但没有进入内核的入口点。如函数 p r i n t f可能调用了系统调用 w r i t e 去执行输出,而函数 s t r c p y (复制一个串 )和a t o i (将A S C I I码转换成整数)完全不涉及操作系统。 从实现者的角度来看,一个系统调用和库函数有着根本的区别。但在用户看来区别并不 严重。例如,在 4 . 4 B S D 中我们运行图1 - 2 中的程序。程序调用了三个函数: s o c k e t 、 s e n d t o和r e c v f r o m,每个函数最终调用了一个内核中同样名称的函数。在本书的后面我们 可以看到这三个系统调用的 B S D内核实现。 如果我们在 S V R 4中运行这个程序,在那里,用户库中的插口函数调用“流”子系统,那 么三个函数同内核的相互作用是完全不同的。在 S V R 4中对s o c k e t的调用最终调用内核 o p e n 系统调用,操作文件 / d e v / u d p并将流模块 s o c k m o d放置到结果流。调用 s e n d t o导致一个 p u t m s g系统调用,而调用 r e c v f r o m导致一个 g e t m s g系统调用。这些 SVR 4的细节在本书 中并不重要,我们仅仅想指出的是:实现可能不同但都提供相同的 A P I给应用程序。 最后,从一个版本到下一个版本的实现技术可能会改变。例如,在 N e t / 1中,s e n d和s e n d t o 是分别用内核系统调用实现的。但在 N e t / 3中,s e n d是一个调用系统调用s e n d t o的库函数: send(int s, char *msg, int len, int flags) { return(sendto(s, msg, len, flags, (struct sockaddr *) NULL, 0)); } 用库函数实现 s e n d的好处是仅调用 s e n d t o,减少了系统调用的个数和内核代码的长度。缺 点是由于多调用了一个函数,增加了进程调用 s e n d的开销。 因为本书是说明 T C P / I P的伯克利实现的,大多数进程调用的函数 (s o c k e t、b i n d、 c o n n e c t等)是直接由内核系统调用来实现。 1.7 网络实现概述 N e t / 3通过同时对多种通信协议的支持来提供通用的底层基础服务。的确, 4 . 4 B S D支持四 种不同的通信协议族: 1) TCP/IP(互联网协议族),本书的主题。 2) XNS(Xerox网络系统 ),一个与 T C P / I P相似的协议族;在 8 0年代中期它被广泛应用于连 www.linuxidc.com Linux公社 www.linuxidc.com
分享到:
收藏