TCP那些事儿·续

2018-09-03  本文已影响0人  Katou_Megumi

1.既然TCP是可靠连接,为什么还会发生丢包?

丢包,指的是接收端发现接收到的数据少了或者有缺失。既然说TCP是可靠传输,为什么还会发生这种丢包的情况呢?

这是因为,TCP保证的是传输是可靠的。而丢包,一般是因为发送端程序本身错误,导致数据根本没有发送出去!或者接收端程序本身有问题,导致数据根本没有接收到!也就是发的数据少了,而不是发的过程中丢了,是程序的问题,而不是TCP的问题。
例如服务器给客户端发大量数据,Send(Unix系统调用)的频率很高,那么就有可能在Send时发生错误(原因可能是又多种,可能是程序处理逻辑问题,多线程同步问题,缓冲区溢出问题等等),如果没有对Send失败做处理重发数据,那么客户端收到的数据就会比理论应该收到的少,就会造成丢数据,丢包的现象。
这种现象,其实本质上来说不是丢包,也不是丢数据,只是因为程序处理有错误,导致有些数据没有成功地被socket发送出去。


2.为什么下载东西速度总是一开始很慢后来逐渐增长到最大?

这是因为TCP的慢启动

引用知乎上的一个例子:

计算机A要向域名abc.com发送100k数据,首先建立连接,但是不是直连,中间会经过路由器,小区交换机,城域网关等等很多中间节点才会到达域名的服务器。对A来说,它并不知道每个中间节点能承受多少缓存。中间节点不可能把所有缓存都给你一个人用,别人也是要用的,也不知道终点服务器的缓存是多少,所以不能一次把所有100k都发送出去。需要“试探”着逐渐增加包的大小,首次少发一点,如果可以的话,下次再大一点,可以的话下次再大一点,一直到最大承载容量为止。
eg.
A向B发送数据的过程如下:
1.A发送10个TCP包给B————发送了14k,剩余86k(每个TCP包的大小是14K左右,这点下文说明)

  1. B告诉A,没有丢包,10个包全部收到(这说明B可以接收至少10个包,中途的任意一个节点也
    可以缓存至少10个包),那么我们下次试试接收12个包,怎么样?
  2. A说,好的,于是再次发送了12个包;——发送了17K,剩余69K
  3. B告诉A,还是没有丢包,我们继续提高到14个包吧~
  4. A说,好的,于是再次发送了14个包;——发送了20K,剩余49K
  5. B告诉A,还是没有丢包,我们继续提高到16个包吧~
  6. A说,好的,于是再次发送了16个包;——发送了22K,剩余27K
  7. B告诉A,还是没有丢包,我们继续提高到18个包吧~
  8. A说,好的,于是再次发送了18个包;——发送了25K,剩余2K
  9. B告诉A,还是没有丢包,我们继续提高到20个包吧~
  10. A说,好的,但是我们只剩下2K了呀~发两个包就够了。再跟上一个结束标记。——发送了
    2K,发送完毕。
  11. B关闭连接。
    于是,100K的请求,实际上是花了6次发送+5次返回(也就是5.5个往返)才完成的。OK,网络传
    输也是有时间的,我们管一次往返的耗时叫RTT。假设一次RTT耗时40毫秒,那么这100K耗时就是
    40*5.5=220毫秒。那么本次发送的带宽,就是100K/0.22s=454KB/S。
    如果文件不是100K,而是10M,花费的次数就远不止5.5次。假设每次都增加2个窗口,并且RTT稳
    定在40ms,大家有兴趣可以算一下10M需要多少次发送,多长时间。
    所以,我们在下载时,总会看到下载速度从一个比较小的速率开始慢慢往上涨。
    那么问题来了。
    *为什么A第一次要发送10个包?多发几个不行吗?
    很遗憾,由于多且复杂的原因,这个值是目前业界能做到的最大值了,并且这也是从最初的4涨上来
    的。至少以目前的网络环境,增加首次请求的窗口数量的话,很容易造成丢包。
    并且,无论你申请的宽带是10M,还是20M,100M,200M,这个值都不会变,除非你和目标服
    务器之间的链路全都受你控制,并且你对它们的性能有充分认识,那么你可以从TCP协议层面修改
    这个值。

3. 下载一个15k文件花费的时间几乎是一个14k文件的1倍,但是下载一个28k的文件花费的时间其实和15k基本一样

这是因为一个TCP请求的大小绝大多数情况下都是14.45k

计算方法:1480 * 10 / 1024 = 14.45k

10即为上文提到的一次最多10个包,TCP每个包大小为1480k,这个在前文第一篇已经讲过

所以有趣的一点是:

前端在优化静态资源的时候,文件大小14k的倍数是一个坎,从28k吐血优化到了15k,除了节省流量,其实在加载速度上几乎没有提升,毫无卵用。

上一篇下一篇

猜你喜欢

热点阅读