网络是怎么连接的—— 2.3 收发数据

Posted 道纪书生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络是怎么连接的—— 2.3 收发数据相关的知识,希望对你有一定的参考价值。

目录

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

2.3.2 对较大的数据进行拆分

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

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

2.3.5 使用窗口有效管理 ACK 号

2.3.6 ACK 与窗口的合并

2.3.7 接收 HTTP 响应消息


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

数据收发操作是从应用程序调用write 将要发送的数据交给协议栈开始的。

一次将多少数据交给协议栈是由应用程序自行决定的,因此如果一收到数据就马上发送出去,就可能会发送大量的小包,导致网络效率下降,所以会将数据存放在内部的发送缓冲区中,积累到一定量再发送。积累多少数据由以下条件判断:

1. 每个网络包能容纳的数据长度。协议栈根据MTU(Maximum Transmission Unit,最大传输单元。)来判断,在以太网中MTU一般是 1500 字节。MTU包含头部,减去头部剩下的才是真正的数据长度,称为MSS(Maximum Segment Size,最大分段大小)。TCP头部+IP头部约为40字节,因此以太网中MSS一般是1460字节。如果TCP/IP增加加密参数等其他信息,头部会增加。

2.时间。如果每次都要等到数据长度达到MSS,会要等半天造成延迟,因此需要一个计数器,超过一定时间就发送。

以上两者其实是互相矛盾的,长度优先则效率高,一次能发送更多的数据,但延迟也高,相反,时间优先延迟低但会造成效率低。如何平衡则看栈协议的开发者怎么写的代码。

应用程序在发送数据时也可以指定一些选项,比如不等待直接发,像浏览器这种会话型的应用程序就是这样。


2.3.2 对较大的数据进行拆分

HTTP消息一般比较短,一个网络包就够。但提交表单,比如我想做编辑的这篇文章,几千个字,那肯定是装不下了,得进行拆分。这个时候就会按照MSS的长度为单位拆分发送。

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

发送网络包之后需要确认对面有没收到,原理如下:

 

首先,TCP 模块在拆分数据时,会先算好每一块数据相当于从头开始的第几个字节,在发送时将这个数据写在 TCP 头部,,“序号”字段就在这时派上了用场。发送数据的长度可以由接收方根据上面说的计算得到。

通过以上两个信息可以检查有没丢包,例如上次接收到了1460字节,下次的包序号为1461则正常,为2921则丢包。接收方将接收到的数据长度加起来写入TCP头部的ACK号中发给发送方,同时将ACK比特设为1表示字段有效。

但实际上序号不是从1开始的,以防通信过程被攻击,这个序号初始值是随机的,需要在收发数据之前告诉对面,通过在前面讲连接时的SYN(Synchronize,同步)设为1时,同时设置序号字段的值实现。

服务器向客户端发数据也是一样的原理。

 

在没有确认之前,发送过的包会保存在发送缓冲区,如果对方没有返回某些包的ACK,则重发,因此,网卡、集线器、路由器都没有错误补偿机制,直接重发就好了。但当断网等情况时,怎么重发都没用,如果TCP尝试重发几次无效之后就会强制结束通信,向应用程序报错。


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

ACK 号的等待时间称作超时时间。

当网络传输繁忙时就会发生拥塞,ACK 号的返回会变慢,这时我们就必须将等待时间设置得稍微长一点,否则可能已经重传了包,前面的 ACK 号才到来,这样就多了次重传,本身网络就拥塞,这下就更堵了。

但如果等待的时间太长,又会导致真的需要重传的包受到影响,所以重传时间也需要衡量。因此,TCP采用动态调整等待时间的方法,TCP发数据时顺便测量ACK号的返回时间,返回的慢则延长时间,返回的快则缩短时间。


2.3.5 使用窗口有效管理 ACK 号

每发一个包等一个ACK再发一个等一个效率太低,因此采用滑动窗口的方式。等ACK的时候也一直发送包,但这样可能导致接收方受不了,处理不过来。

当接收方的TCP收到包后,将数据存放到接收缓冲区,然后计算ACK,组装数据传给应用程序。如果还没完成下一个包就到了,这个包也会存放到缓冲区。但缓冲区如果也塞满了,也会溢出,后面的数据进不来,怎么解决呢?

首先,接收方告诉发送方自己最多能接收多少数据(称为窗口大小,一般和接收方的缓冲区大小一致),发送方根据这个值对数据发送操作进行控制,这就是滑动窗口方式的基本思路,具体操作直接看图。

 


2.3.6 ACK 与窗口的合并

更新窗口大小的时机应该是接收方从缓冲区中取出数据传递给应用程序的时候。

而当接收方收到数据时,如果确认内容没有问题,就应该向发送方返回 ACK号,因此我们可以认为收到数据之后马上就应该进行这一操作。

这样的话,每收到一个包,就需要向发送方分别发送 ACK 号和窗口更新这两个单独的包,效率下降。因此,接收方在发送 ACK 号和窗口更新时,并不会马上把包发送出去,而是会等待一段时间,在这个过程中很有可能会出现其他的通知操作,这样就可以把两种通知合并在一个包里面发送了。比如应用程序连续请求了数据,连续发生了窗口更新,只要发送最后的结果即可。


2.3.7 接收 HTTP 响应消息

浏览器接收web服务器的响应消息也需要协议栈的参与。和发送数据一样,接收数据也需要将数据暂存到接收缓冲区中,当协议栈尝试将缓冲区中诉苦传给应用程序时,可能因为响应消息还没返回,接收缓冲区中并没有数据,这时该任务就会被挂起,等返回消息到达之后再继续。协议栈这时会去处理其他应用程序的工作。


本节完。

 

 

以上是关于网络是怎么连接的—— 2.3 收发数据的主要内容,如果未能解决你的问题,请参考以下文章

网卡收发数据包数量大的惊人如何解决

java网络编程——多线程数据收发并行

2.网络是怎么连接的 --- 用电信号传输TCP/IP数据

实战BLE蓝牙之数据收发

网络通信——TCP协议了解TCP协议的数据收发机制吗?说说收发阶段有哪些功能会导致延时

[架构之路-45]:目标系统 - 系统软件 - Linux OS硬件设备驱动-网络驱动程序模型网络数据包的收发流程