未决连接队列
在内核中,内核为任何一个给定的监听套接字(被动 socket)维护了一个未决连接队列,该队列分为两个部分,分别是未完成连接队列和已完成连接队列
这个两个队列元素个数之和不超过 backlog,这是函数 listen 的参数(但现在listen的参数好像没用了)。
MSS
MSS,最大报文段长度。在连接建立的时候,即在发送 SYN 段的时候,同时会将 MSS 发送给对方(MSS 选项只能出现在 SYN 段中!!!!!!),告诉对端它期望接收的 TCP 报文段数据部分最大长度。
其他选项后文介绍
MSS的作用
控制报文段数据大小。
如果 TCP 报文段传输的数据只有一个字节,在 IP 层传输的数据报大小就是 40 + 1 = 41 字节(至少 20 字节的 IP 头 + 20 字节的 TCP 头 + 1 字节数据)。这样网络的利用率就只有 1/41. 传输n 字节的数据利用率就是 n/(n+40),显然 TCP 报文段传输的数据如果越大,网络利用率就越高。
但是实际上并非如此。因为网络传输数据时,数据是最终是要交付到链路层协议上的,也就是说最后要封装 成“帧”。二型以太网规定,帧大小不能超过1518字节(14 字节的帧头 + 4 字节帧校验 和 + 最多 1500 字节数据)。所以 IP 数据报的大小如果超过了 1500 字节,要想交付给链路层就必须进行“分片”。
“分片”指的是一个 IP 数据报太大,需要拆分成一个一个的小段,变成多个 IP 数据报。
所以我们希望一个数据包不要超过1500字节,IP数据报的首部占20字节,TCP报文段首部占20字节,所以TCP报文段数据不能超过1460字节。
MTU
链路层对这种帧数据长度的限制称为最大传输单元(MTU)
MTU与MSS的区别
- MSS 是软件层的概念,它是由软件控制的
- MTU 是硬件(比如网卡出口)的属性,是指二层链路层帧携带的数据最大大小。
FIN_WAIT2
FIN_WAIT2是主动发起关闭的一端在等待对端FIN时的状态(即对端处于CLOSE_WAIT状态等待数据发送完毕)
这时如果对端在CLOSE_WAIT状态时断电或断网了,主动关闭一方将永远处于FIN_WAIT2状态,Linux为了防止这样的情况发生,设置了一个定时器,如果这个连接空闲 10 分钟 75 秒,TCP 将 进入 CLOSED 状态。实际上,这是违反协议的,但又未尝不可呢?
连接异常与RST
当 TCP连接出现严重的错误时,必须释放连接。通过将 TCP 首部中的 RST 标志位置 1,就可以通知对端发生错误, 以终止连接。
正常情况下,关闭连接的方式是发送 FIN 段,即四次挥手。这种方式也称为有序释放(orderly release)。 也可以通过发送 RST 段给对端来释放连接,这种方式称为异常释放(abortive release)。 异常终止连接有两个特点:
- 丢弃任何尚未发送的数据,立即发送 RST 报文段
- RST 接收方会区分另一端是异常关闭还是正常关闭,从而做出不同响应
可以指定选项 SO_LINGER,发起异常关闭请求(SO_LINGER将来会讲),客户端在 close 的时候会发送 RST 段而不是正常的 FIN 段。
注意,主动发送 RST 段的一方,不会进入 TIME_WAIT 状态。
半打开
如果一方已经关闭或异常终止,而另一方却对此毫不知情,这种连接就称为半打开的。
考虑一种情况,A和B建立了TCP连接,但此时B断网或宕机了,此时A想给B发送数据,接下来有三种情况:
- B任然关机
- B重启了但未启动服务
- B重启并启动了服务
结论
处于半连接的 A 向主机 B 发送数据:
- 如果主机 B 仍然断网或者已经连接上网络,但是服务未启动,A 向 B 发送数据,经过数次超时重传后放弃连接, 并发送 RST 段给对方(不一定非得发送,这系统实现有关)。
- 如果主机 B 已经连接上网络且重新启动了服务,A 向 B 发送数据,B 收到后因为不认识这个连接,向 A 发送 RST 段。
同时关闭的情况
具体见TCP连接状态图
PSH字段
当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。发送方TCP把PSH置1.接受方收到时就会尽快交付接受应用进程,而不再等到整个缓存都填满了再向上交付。
对于发送方通常来说,每次write,TCP会将数据转化为一个或多个数据报,并将最后一个TCP报文段标记为PSH.
举个例子,如果发送方每次发送1024字节,发送8次,那么接受方用循环来读的话也是读8次每次1024字节。因为每次write就会在最后标记PSH接受方收到后就会立即交付上层。如果发送方一次性发送8192字节,接受方也会只收到8192字节,因为发送方只在最后标记了PSH,所以只会交付一次。