目录
确认应答
延时确认应答
Nagle算法
确认应答
TCP在传输数据的时候,每次接受方收到来自发送方的数据包后,接受方对都会发送一个确认应答(ACK)报文作为回应,发送方收到来自接受方的确认应答(ACK)报文,就表明发送的数据已经被对方收到。
但是网络传输存在拥堵的情况,是很有可能出现"后来者居上"的情况,这个时候就不能只通过收到数据的顺序来的确定发送数据的情况。
那有没有好的办法来解决这个问题? 通过序列号seq和确认序列号ack
由于TCP是面向字节流传输的数据,所以序列号seq和确认序列号ack是以字节为单位进行编号的。针对每个字节分别编号,依次进行累加。
那么初始的序列号seq和确认序列号ack是是如何确定的呢?
就是通过TCP三次握手
序列号和确认序号是如何工作的呢?
举个例子
客户端向服务发送了1000个字节的数据。假设这个数据报的序列号为1,那么服务器给客户端回应的确认应答(ACK)报文的确认序列号ack则为1001。
意思就是1001之前的数据,服务器已经收到,下次发送数据的时候,请从1001开始发送。
但序列号的作用不仅仅是应答的作用。接收方可以根据序列号将接收到的数据进行排序,并且去掉重复的数据。
延时确认应答
接收方如果每次收到来自发送发的数据包后都立刻回复确认应答的话,可能会返回一个较小的窗口,这个窗口是用来通知发送方下次发送数据的大小。主要是因为接收方会先将数据放到缓冲区,待上层应用层将这些数据取走。而由于刚收到数据,应用层还没来得及取,此时缓冲区的可用空间变小,就会通知发送方要减少下次发送的数据长度。
当接收端收到这个小窗口的通知以后,会以它为上限发送数据,从而又降低了网络的利用率。
除此之外,如果只是单纯的发送一个确认应答,代价又会很高。因为IP头部有20字节,TCP头部也有20字节(此处不计选项)。
那么有没有好的办法解决这个问题呢?
延时确认应答 Delay ACK
延时确认应答将几个ACK应答组合在一起成为单个应答,或者希望应用程序会对刚刚收到的数据进行应答,这样就可以用新数据将ACK应答捎带过去,就像做顺风车一样。
这里有个捎带应答的概念
TCP的确认应答和回执数据可以通过一个包发送。这种方式叫做捎带应答
- 当有回执数据要发送时,TCP的确认应答会随回执数据通过一个包发送。
- 如果没有回执数据时,TCP的确认应答会等待一段时间,看看稍后是不是有回执数据要发送。Windows默认等待时间为200ms,Linux默认等待时间为40ms。
- 如果在等待回执数据的时候,第二个数据包又到达了,这是要立即发送确认应答。
Nagle算法
Nagle怎么读?
Nagle算法是TCP为了提高网络利用率和减少网络发送数据包经常使用的算法。
如果发送一字节有用的数据,就会产生至少41个字节长的数据包,20字节的IP头部和20字节的TCP头部(这里没有算上选项,所以说至少41字节),这样就导致了为了发送一字节有用的数据,却浪费掉了40字节的的头部信息,这会导致网络效率非常的低。
而且在广域网上,大量TCP Small Packet(数据包)会很有可能造成网络的拥塞。
Nagle算法为了减少TCP Small Packet(数据包)的出现和提高网络利用率,它要求一个TCP连接上最多只能有一个未被确认的小数据段。
在该小数据段的确认应答到达之前不能发送其他小数据段。
而且TCP会收集小的数据段,等之前的数据段的确认应答收到后,将这些收集小的数据段打包成一个数据段发送出去。
Nagle算法的伪代码:
if (有数据要发送){
if(可用窗口的大小 >= MSS && 可发送的数据 >= MSS){
立即发送MSS长度的数据
}else {
if (有未确定的数据){
将数据放入缓存等待未确定数据的ACK
}else {
立即发送数据
}
}
}
虽然Nagle算法可以提高网络的利用率和减少小的数据包,但是这也是要分情况的。因为Nagle算法会造成某种程度上的延迟。
所以在实时性要求很高的交互上,比如网络游戏、机器控制等领域使用TCP时往往会关闭对该算法的启用。