这节课,我们简述下网络中的数据收发过程。

1.网络包的形成

在完成网络连接后,就进入到数据收发阶段。

使用Socket中的Write(…)接口将数据写到发送缓冲区中。写进缓冲区的数据并不会立即被发送出去。而是等到缓冲区数据到达一定的长度或者发送时间限制后才将包转交给IP层。这样做的原因是因为应用程序一次写入的数据是无法确定长度的,如果每次都直接封装成包发送出去,就会造成网络上有大量的小包,导致网络效率下降,但如果一直因为数据不够而不发送,又会造成较大的延迟。所以协议栈就规定了一个称为MTU的标准来确定发包的大小。

MTU表示一个网络包的最大长度,在以太网中一般为1500字节。MTU是包含所有头部和数据的总长度。其中,数据的最大长度叫做MSS。如下图:
lesson3 简单网络连接-网络数据的收发
所以,缓冲区一般到达MSS规定的长度就会被发送出去。

但如果缓冲区数据过长,就需要进行数据拆分。在拆分出来的各个数据的前面加上各种头部。见下图:

lesson3 简单网络连接-网络数据的收发

2.使用ACK号确认网络包已收到

TCP是一种可靠的数据传送,发出去的包要收到响应进行确认,丢包后会重新发送。这个确认原理分为几个步骤:

  • 首先,TCP模块在拆分数据时,会先计算好每一块数据相当于头部开始的第几个字节(累加),接下来在发送这一块数据时,将计算好的字节数写在TCP头部中,“序号”这个字段就是用来干这个的。
  • 然后,发送数据的长度也需要告知对方,不过这个并不是放在TCP头部里面的,因为用这个网络包的长度减去头部的长度就可以得到数据的长度,所以接收方可以用这种方式来进行计算。
    lesson3 简单网络连接-网络数据的收发

假设上次收到第1460字节(接收方计算),那么接下来如果收到的是序号(ACK序号)为1461的包,说明中间没有遗漏;但如果收到的包序号为2921,那就说明中间有包遗漏了。

在实际过程中,ACK号并不是从1开始的(随机正整数),在连接阶段发送的ACK号就是这里的起始序号。

同理,服务器向客户端发送数据包的时候也是使用ACK号进行确认的。

lesson3 简单网络连接-网络数据的收发

3.TCP包的一些控制

TCP传输除了具体可靠性外,还可以调节发送包的平均时间。

当网络传输繁忙时就会发生阻塞,ACK号的返回就会变慢,我们需要将等待时间(Timeout指标)设置得稍微长些,否则可能因为ACK号的姗姗来迟导致包重发的浪费。TCP采用了动态调整等待时间的方法,这个等待时间是根据ACK号返回所需的时间来判断的。具体来说,TCP会在发送数据包的过程中持续测量ACK号的返回时间,如果ACK号返回变慢,则相应延长等待时间;相应地,如果ACK号马上就能返回,则相应缩短等待时间。

多包的同时发送:如果发出了TCP包后只是在等待ACK包的返回,这样就浪费了很多网络资源。为了避免这种情况,TCP采用了滑动窗口方式进行发包操作。

lesson3 简单网络连接-网络数据的收发
使用窗口滑动方式发送数据包要注意发送包的个数限制,如果发送包比接收方处理包的速度快,在将数据存储到接收缓冲时,造成缓冲区溢出。缓冲区溢出后,后面的数据就进不来了,因此接收方就收不到后面的数据了。

可以通过以下方式解决:

  • 首先,接收方需要告诉发送方自己最多能接收多少字节数据。
  • 然后,发送方根据这个值对数据发送操作进行控制。

这也就是TCP头中窗口字段的作用。

lesson3 简单网络连接-网络数据的收发

发送方的数据到达接收方,在接收完成后就需要向发送方返回ACK号,再经过一段时间,当数据传递给应用程序之后才需要更新窗口大小。这样,时间上就有一定的间隔。所以,接收方收到包后不会立马返回ACK包给到发送方,而是要等待一段时间,在这个过程中很有可能会出现其他的通知操作,这样就可以把两个值写在同一个ACK包里了。

4.接收HTTP响应消息

发送HTTP请求消息后,接下来还需要等待Web服务器返回响应消息。之后的操作分为以下几个步骤:

  • 浏览器在发送消息后,会调用read(…)接口来获取响应消息。这个过程是阻塞的,直到接收缓冲区有数据后,通过系统中断方式通知到浏览器进行数据读取。
  • 控制流程会通过read转移到协议栈,然后协议栈执行接下来的操作。

相关文章: