美文网首页
收发数据(2.3)

收发数据(2.3)

作者: cdd48b9d36e0 | 来源:发表于2018-07-08 16:06 被阅读13次

2.3 收发数据

2.3.1 将HTTP请求消息交给协议栈

“协议栈并不是一收到数据就马上发送出去,而是会将数据存放在内部的发送缓冲区中,并等待应用程序的下一段数据。”其中,因素有二:
“第一个判断要素是每个网络包能容纳的数据长度。。。当从应用程序收到的数据长度超过或者接近 MSS 时再发送出去,就可以避免发送大量小包的问题了。”
“另一个判断要素是时间。当应用程序发送数据的频率不高的时候,如果每次都等到长度接近 MSS 时再发送,可能会因为等待时间太长而造成发送延迟,这种情况下,即便缓冲区中的数据长度没有达到 MSS,也应该果断发送”


MTU与MSS

“MTU:一个网络包的最大长度,以太网中一般为 1500 字节。”
“MSS:除去头部之后,一个网络包所能容纳的 TCP 数据的最大长度。”

2.3.2 对较大的数据进行拆分

“HTTP 请求消息一般不会很长,一个网络包就能装得下,但如果其中要提交表单数据,长度就可能超过一个网络包所能容纳的数据量,比如在博客或者论坛上发表一篇长文就属于这种情况。”


应用程序数据的拆分发送

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

“到这里,网络包已经装好数据并发往服务器了,但数据发送操作还没有结束。TCP 具备确认对方是否成功收到网络包,以及当对方没收到时进行重发的功能,因此在发送网络包之后,接下来还需要进行确认操作。”


序号和 ACK 号的用法

“通过这些信息,接收方还能够检查收到的网络包有没有遗漏。例如,假设上次接收到第 1460 字节,那么接下来如果收到序号为 1461 的包,说明中间没有遗漏;但如果收到的包序号为 2921,那就说明中间有包遗漏了。像这样,如果确认没有遗漏,接收方会将到目前为止接收到的数据长度加起来,计算出一共已经收到了多少个字节,然后将这个数值写入 TCP 头部的 ACK 号中发送给发送方 34 。简单来说,发送方说的是“现在发送的是从第 ×× 字节开始的部分,一共有 ×× 字节哦!”而接收方则回复说,“到第 ×× 字节之前的数据我已经都收到了哦!”这个返回 ACK 号的操作被称为确认响应,通过这样的方式,发送方就能够确认对方到底收到了多少数据。”

“返回 ACK 号时,除了要设置 ACK 号的值以外,还需要将控制位中的 ACK 比特设为 1,这代表 ACK 号字段有效,接收方也就可以知道这个网络包是用来告知 ACK 号的。”

“在实际的通信中,序号并不是从 1 开始的,而是需要用随机数计算出一个初始值,这是因为如果序号都从 1 开始,通信过程就会非常容易预测,有人会利用这一点来发动攻击。因此需要在开始收发数据之前将初始值告知通信对象。大家应该还记得在我们刚才讲过的连接过程中,有一个将 SYN 控制位设为 1 并发送给服务器的操作,就是在这一步将序号的初始值告知对方的。实际上,在将 SYN 设为 1 的同时,还需要同时设置序号字段的值,而这里的值就代表序号的初始值 ”
“TCP 采用这样的方式确认对方是否收到了数据,在得到对方确认之前,发送过的包都会保存在发送缓冲区中。如果对方没有返回某些包对应的 ACK 号,那么就重新发送这些包。”
“这一机制非常强大。通过这一机制,我们可以确认接收方有没有收到某个包,如果没有收到则重新发送,这样一来,无论网络中发生任何错误,我们都可以发现并采取补救措施(重传网络包)。反过来说,有了这一机制,我们就不需要在其他地方对错误进行补救了。”
“因此,网卡、集线器、路由器都没有错误补偿机制,一旦检测到错误就直接丢弃相应的包。应用程序也是一样,因为采用 TCP 传输,即便发生一些错误对方最终也能够收到正确的数据,所以应用程序只管自顾自地发送这些数据就好了。不过,如果发生网络中断、服务器宕机等问题,那么无论 TCP 怎样重传都不管用。这种情况下,无论如何尝试都是徒劳,因此 TCP 会在尝试几次重传无效之后强制结束通信,并向应用程序报错。”

小结:TCP通过“序号”和“ACK 号”可以确认接收方是否收到了网络包。

2.3.4 根据网络包平均往返时间调整 ACK 号等待时间

“前面说的只是一些基本原理,实际上网络的错误检测和补偿机制非常复杂。下面来说几个关键的点,首先是返回 ACK 号的等待时间(这个等待时间叫超时时间)。”
“正因为波动如此之大,所以将等待时间设置为一个固定值并不是一个好办法。因此,TCP 采用了动态调整等待时间的方法,这个等待时间是根据 ACK 号返回所需的时间来判断的。具体来说,TCP 会在发送数据的过程中持续测量 ACK 号的返回时间,如果 ACK 号返回变慢,则相应延长等待时间;相对地,如果 ACK 号马上就能返回,则相应缩短等待时间 。”

2.3.5 使用窗口有效管理 ACK 号

一来一回方式和滑动窗口方式
滑动窗口与接收缓冲区

“前面提到的能够接收的最大数据量称为窗口大小 ,它是 TCP 调优参数中非常有名的一个。(一般和接收方的缓冲区大小一致)”

2.3.6 ACK 与窗口的合并

“首先,什么时候需要更新窗口大小呢?当收到的数据刚刚开始填入缓冲区时,其实没必要每次都向发送方更新窗口大小,因为只要发送方在每次发送数据时减掉已发送的数据长度就可以自行计算出当前窗口的剩余长度。因此,更新窗口大小的时机应该是接收方从缓冲区中取出数据传递给应用程序的时候。这个操作是接收方应用程序发出请求时才会进行的,而发送方不知道什么时候会进行这样的操作,因此当接收方将数据传递给应用程序,导致接收缓冲区剩余容量增加时,就需要告知发送方,这就是更新窗口大小的时机。”
“那么 ACK 号又是什么情况呢?当接收方收到数据时,如果确认内容没有问题,就应该向发送方返回 ACK 号,因此我们可以认为收到数据之后马上就应该进行这一操作。”
“因此,接收方在发送 ACK 号和窗口更新时,并不会马上把包发送出去,而是会等待一段时间,在这个过程中很有可能会出现其他的通知操作,这样就可以把两种通知合并在一个包里面发送了。举个例子,在等待发送 ACK 号的时候正好需要更新窗口,这时就可以把 ACK 号和窗口更新放在一个包里发送,从而减少包的数量。当需要连续发送多个 ACK 号时,也可以减少包的数量,这是因为 ACK 号表示的是已收到的数据量,也就是说,它是告诉发送方目前已接收的数据的最后位置在哪里,因此当需要连续发送 ACK 号时,只要发送最后一个 ACK 号就可以了,中间的可以全部省略。当需要连续发送多个窗口更新时也可以减少包的数量,因为连续发生窗口更新说明应用程序连续请求了数据,接收缓冲区的剩余空间连续增加。这种情况和 ACK 号一样,可以省略中间过程,只要发送最终的结果就可以了。”

小结:接收方需要回馈两个信息:ACK和窗口大小,但是并不是老老实实的一条一条专门回馈,而是会互相等待最适宜的时机一起发送,包括连续发送时只需要发送最后一个即可的策略

相关文章

网友评论

      本文标题:收发数据(2.3)

      本文链接:https://www.haomeiwen.com/subject/fgsouftx.html