2.3.1 将HTTP请求消息交给协议栈
- 首先,协议栈不关心应用程序传来的数据是什么内容,在协议栈看来,发送的数据就是一定长度的二进制字节序列。
- 其次,协议栈并不是一收到数据就立马发送,而是将数据存放在发送缓冲区,并等待应用程序的下一段数据。积累多少数据才发送取决于以下几个因素:
a. 网络包能容纳的数据长度,即MTU,包含头部的长度,数据长度称为MSS,TCP/IP头部长度一般是40,MTU一般是1500,所以MSS是1460。
b. 等待时间。协议栈内部有一个计时器,经过一段时间之后,就把网络包发出去。 - 具体由哪个因素决定,应用程序在调用write时可以指定。
2.3.2 对较大的数据进行拆分
发送数据大于MSS时,数据就会被拆分到不同的网络包中进行发送,每个网络包会加上TCP头部,标记出收发双方的端口号,再交由IP模块来发送。
2.3.3 使用ACK号确认网络包已收到
- TCP具备确认对方是否成功收到网络包,以及对方没收到进行重发的功能,因此接收方需要有确认操作。
- 发送数据拆包时会将序号下在TCP头部,接收方通过返回确认包中的ACK告诉发送方,到第xxx号字节之前的数据已经都收到了。
- 实际通信中,序号并不是从1开始的,而是随机数,避免被攻击。
- 由于通信是双向的,所以客户端和服务器都需要计算自己的序号。
- 重发机制:在得到对方确认之前,发送过的包都保存在发送缓冲区中,如果对方没有返回某些包对应的ACK号,就重新发送这些包。如果重传几次都无效,就会强制结束通信,并向应用程序报错。
2.3.4 根据网络包平均往返时间调整ACK号等待时间
TCP在发送数据的过程中持续测量ACK号返回时间,根据时间快慢调整等待时间。
2.3.5 使用窗口有效管理ACK号
- 等到ACK的时间内,如果什么都不做,效率很低。
- TCP采用滑动窗口的方式,提高效率。滑动窗口,就是在发送一个包后,不等待ACK号返回,直接发送后续的一系列包,这样一来,等待ACK的时间就被利用了。
- 如果接收方处理接收数据的速度慢于发送方发出数据的速度,就会造成缓冲区溢出。因此,滑动窗口方式下,接收方通过头部窗口字段告诉发送方自己当前最多能接收多少数据,然后发送方根绝这个值对数据发送操作进行控制。
2.3.6 ACK与窗口的合并
- 当接收方将数据传递给应用程序,导致接收缓冲区剩余容量增加时,就需要告诉发送方,这是更新窗口大小的时机。
- ACK是收到数据确认没问题后就立刻告诉发送方。
- 如果按上面的方式,接收方发送窗口更新和ACK需要用两个包,效率很低。
- 因此接收方在发送ACK和窗口更新时,会等待一段时间,这个过程中如果有其他通知操作,就可以合在一个包内发送。
2.3.7 接收HTTP消息
首先,协议栈会检查收到的数据块和头部的内容,判断是否有数据丢失,没有问题则返回ACK号。然后协议栈将数据块暂存到接收缓冲区,并将数据块按顺序连接起来还原出原始数据,最后将数据块交给应用程序。
网友评论