前言
本章提供本书示例所有TCP/IP协议的概貌。主要涉及TCP连接和终止、状态转换图、TIME_WAIT状态和UDP概述(第一次拜读忽略了SCTP)
关注点
- TCP/IP协议概况
- 用户数据包协议UDP
- 传输控制协议TCP
TCP/IP协议概况
ICMP 网际消息控制协议 处理在路由器和主机之间流通的错误和控制消息。
IGMP 网际组管理控制协议 用于多播
ARP 地址解析协议 把一个ip地址映射成MAC地址
RARP 反向地址解析协议 把MAC地址映射成ip地址
BPF BSD分组过滤器 该接口提供对于数据链路层的访问能力
DLPI 数据链路提供者接口 该接口也具有数据链路层的访问能力
用户数据报协议UDP
UDP提供无连接的、不可靠的数据报协议
关于UDP编程的具体情况讲在后续章节做详细介绍。
传输控制协议TCP
关于三路握手
SYN、ACK的值分别起什么作用?
SYN:[RFC0793]Initial Sequence Number ISN:specifies that ISN should be viewed as a 32-bit counter that increments by 1 every 4微妙。
ISN是一个随系统时钟变化的初始序号
功能之一是为一个连接的报文段安排序列号,以防止出现与其他连接的序列号重叠的情况。
功能之二是防止攻击
现代linux系统的实现更加复杂。详见《TCP/IP详解1》
ACK:ACK是对SYN的确认,其值位对端SYN值+1,表示着期待下一个要接收的SYN的值。
为什么不是两次或四次?
TCP三次握手握的是什么?握的是双方的初始序列号,这样就需要两次,但是后面以此需要确认机制来保证TCP的可靠性,那么就是三次,TCP协议规定不对ACK回复ACK,就是经典的红蓝军问题:世界上不存在完全可靠的通信协议,最后的确认也只是保证相对可靠。
关于四次挥手
什么是半关闭?
这个问题关系到close和shutdown的讨论,将在后面解答。
四次挥手可以是三次吗?
可以三次。但是一般状态下四次。
主动关闭端发送的FIN要求对端马上回复ACK,但是此时对端可能还有数据要发送给主动关闭端,或者处于忙状态,这时候就是四次握手。当然把ACK和FIN做捎带确认给主动关闭端形成三次挥手也是可以的。(这里不讨论两端同时关闭的状态)
关于TIME_WAIT状态
TIME_WAIT状态为什么会存在?
(1)保证可靠地实现TCP全双工连接的终止;
(2)允许老的重复分节在网络中消逝(2MSL)
TIME_WAIT状态有什么危害?
(1)对服务器:短时间关闭大量的client连接,会造成服务器上出现大量的TIME_WAIT连接,占据大量的tuple,严重消耗者服务器的资源。
(2)对客户端,毕竟端口只有65535个,客户端端口可能被耗尽(所以如果客户端需要连接本机的一个服务的时候,首选Unix域套接字而不是TCP)
TIME_WAIT状态怎么避免?
状态流转图
缓冲区大小
MTU 以太网 1500字节 如果从某个接口送出时,ip数据报超过MTU,那么将会被执行分片
MSS 经常设为MTU-20个字节的TCP头部-20个字节的UDP头部 = 1460
TCP输出–两种异常情况及其处理
write阻塞
当调用write时,内核从应用进程的缓冲区中复制所有数据到所写套接字的发送缓冲区,如果该缓冲区容不下,那么write阻塞。直到能容下,write返回。
注意:write调用返回仅仅表示应用缓冲区中的所有数据都复制到套接字发送缓冲区,并不表明对端已经接收到数据。
丢包
如果数据链路的输出队列已满,那么新到的分组将被丢弃,因此TCP必须为已发送的数据保留一个副本,直到它被对端确认为止。(TCP滑动窗口中已发送并未确认字段)
UDP输出
UDP是不可靠协议,因此它没有一个真正的发送缓冲区,但是有一个虚拟的,可以通过SO_SNDBUF控制的虚拟缓冲区,如果一个应用进程写一个大于套接字发送缓冲区大小的数据报,内核将返回该进程一个EMSGSIZE错误。出错的报将被丢弃。
注意:write调用成功返回表示所写的数据报或所有片段已被加入数据链路层的输出队列。如果不是会放回ENOBUFS错误,这点与TCP不同,TCP应用层因为有缓冲区可以重新发送察觉不到这种情况
端口
说到端口突然想起一个有意思的话题,端口和多线程多进程的关系:
单个进程监听多个端口
单个进程创建多个 socket 绑定不同的端口,TCP, UDP 都行
多个进程监听同一个端口(multiple processes listen on same port)
通过 fork 创建子进程的方式可以实现,其他情况下不行。当连接到来时,子进程、父进程都可以 accept, 这就是著名的“惊群”问题(thundering herd problem)。