TCP:传输控制协议
首先我们来看看TCP的协议格式:
- 源/目的端口号表示数据从哪个进程来去哪个进程.
- 32位序号/32位确认序号:在数据传送时标识数据的发送端已发送的和接收端确认消息收到后确认的对应的数据.(实现确认机制和超时重传机制)
- 4位TCP报头,在图中已经给出解释.
- 6个标志位
①URG:紧急指针是否有效
②ACK:确认号是否有效
③PSH:提示应用程序接收端立刻从TCP缓冲区把数据读走.
④RST:对方要求重新建立连接.(复位报文段)(若链接建立失败,该标志为就是1)
⑤SYN:请求建立连接(同步报文段)
⑥FIN:通知对方,本段要进行关闭了(结束报文段) - 16位窗口大小:接收端的缓冲区的剩余大小.
- 16位校验和:发送端填充,CRC校验,若接收端校验与发送端的校验结果不同,则说明数据错误.
- 16位紧急指针:表示哪部分数据时紧急数据
3次握手以及4次挥手
建立连接的过程:
断开连接的过程:
四次挥手最后的TIME_WAIT是哪一方先发起断开然后那一方就会进行TIME_WAIT状态,TIME_WAIT的时长为2MSL,MSL是从一端到另外一端的最长时间,在Linux操作系统中,Centos7默认的值是60s.
问题:为什么三次握手可以合二为一而四次挥手却不可以?
因为在四次挥手中,如果是A方先发起的关闭连接请求,B方在收到时可能数据还没有读完,但是此时如果等待B方处理完自己的事情再回复,A方就可能因为长时间收不到回复而进行重传请求.所以在B收到A的关闭请求后,操作系统就会立即给A回复一个确认求情,然后B在处理完自己的事情后再给A发请求关闭.
为什么四次挥手中先申请关闭的一方要进行TIME_WAIT等待?
因为为了保障最后一个可靠报文到达,假设此时最后一个ACK报文丢失了,那么对端就会重新再发一次FIN,这样就可以保证最后的确认信息可靠到达.
在服务器的TCP连接没有完全断开的情况下不允许重新监听,某些情况下是不合理的:
确认应答机制(ACK)
目的:保障可靠性.
例如:
我们看到图中,数据都有编号.那么这就是序列号.
并且每个序列号都有对应的确认序列,确认序列的含义:已经收到的数据和下一个数据从哪一个开始.
超时重传机制
目的:保证数据的可靠性
如果在数据传输中发生了丢包现象.
情况一:数据报文丢失
主机A给主机B发送了数据后,数据无法再规定的时间内到达主机B.主机A就会重新传输数据给数据B.
情况二:确认报文丢失
如果在规定的时间内没有收到确认报文,那么主机A也会进行数据重传,那么此时主机B可能会收到多份重复的数据,那么此时TCP协议就要可以识别出来哪些报文是重复的,并且对调重复的数据.此时就可以序列号就可以做到去重的效果,在接收到数据时进行查看收到的数据中是否有该数据,若有,则丢弃.
问题:超时重传的数据怎么确认?
- 最理想的情况就是找到一个最小的时间,保证”确认应答一定能在这个时间内返回”.
- 时间的长短会随着网络环境的不同而有所差异.
- 如果超时时间设置的太长,就会影响整体的传输效率.
- 如果超时时间设置的太短,就可能会频繁的发送重复的数据包.
TCP为了保证在任何环境下都能有较高效能的通信,因此会动态的计算这个超大的时间.
在Linux环境中,超时以500s为一个单位进行控制,每次判定超时重传的超时时间都是500s的整数倍.
如果第一次重传后仍然未收到应答,那么此时的超时时间就变成了2*500s.
第二次就会变成4*500s…….8*500….(以指数的形式递增)
当累积到一定的重传次数后,TCP就会认为网络或者对端主机出现了异常,因此就会强制关闭连接.
滑动窗口
目的:提高传送的效率.
在确认应答中,如果进行一传一确认的机制进行,可是效率会低很多,确认应答也是在跨网络进行的,所以传输数据的效率就会很低.
所以,就引进了滑动窗口的机制,可以一次发送多条数据,这样就可以大大的提高性能.
如下图:
图中的窗口大小就是无需等待确认应答而可以传送的数据的最大值.图中的窗口大小就是:4000个字节.
当收到第一个确认应答后,滑动窗口就会向后移,继续发送后面的数据段.操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前有哪些数据没有应答,数据被确认应答后才从缓冲区删掉.
窗口越大,网络的吞吐量就越大.
滑动窗口如下:
如果一次发送多个数据,出现了丢包现象该怎么办?
情况一:确认应答ACK丢包
如下图:
在这样的情况下,数据报收到而数据确认丢失,这样是很好解决的,可以在后续的确认中进行确认.例如图中的数据1~1000的确认应答ACK丢失了,而在收到1001~2000的数据时,此时确认应答的数据就是1~2000的数据。
每次确认的数据是:当前接收端收到的所有数据的编号. |
情况二:数据包丢失
快重传机制
如下图所示:
如上图所示:当数据包丢失时,此时数据的确认应答ACK包返回的就是当前已经收到的数据,当超过一定的次数之后,就会将之前那个没有收到确认的数据包进行重传。例如图中丢失的数据包是数据1001~2000的数据,以后的几个数据的确认应答都是数据1001以前的数据。在重传1001~2000的数据后,主机B确认收到在返回ACK时就变成了当前接收缓冲区的所有数据。
在接收端收到数据包后,会将数据先放入接收缓冲区中。 |
流量控制
目的:提高数据传输的可靠性。
比如主机A给主机B发送数据时,主机B的处理数据的速度是有限的,如果主机A发送的太快,而导致主机B的接收端已满,那么此时若主机A继续发送数据给主机B,就会导致数据丢失.那么就会引起一系列的超时重传,快重传等连锁反应.
所以TCP支持根据接收端的处理能力,来决定发送端的发送速度.这个机制就叫做流量控制. |
- TCP协议中有一个’16位窗口大小的字段’,所以接收端就可以将自己现在空闲的缓冲区的大小通过ACK(确认应答)返回给发送端.
- 若接收端发现自己的缓冲区快满了,就会将窗口大小设置为一个更小的数字通知给发送端.
- 当发送端接受到这个消息时,就会调整自己的发送速度.
- 那么,如果接受端的缓冲区已满并且没有来得及处理数据,发送端就会收到接收端的缓冲区大小为0的通知.那么发送方就不会发送数据给接收端了,但是会定期发送一个窗口探测数据段,获取接收端的空闲缓冲区的大小.
拥塞控制
目的:提高数据的可靠性.
虽然TCP有滑动窗口可以提高数据的高效发送,但是如果网络状态比较拥堵,如果在不清楚网络状态的情况下,贸然发送大量的数据,无疑是雪上加霜.
所以,TCP就引入了慢启动的机制,先发送少量的数据,试探一下网络的状态,然后再决定传输数据的速度.
比较滑动窗口,流量控制中的窗口以及拥塞控制中的窗口:
延迟应答
目的:提高数据传输的效率.
现在我们设想一下这样的场景:
- 接收端的缓冲区大小为1M,一次收到500k的数据;此时如果立即应答,那么返回的窗口大小就是524k.
- 但是实际上CPU的处理速度非常的快,可能在几毫秒之内就可以把收到的数据给处理完.
- 所以,在这样的情况下,如果返回给的发送端窗口再大一些,无疑接收端也是可以处理的,并且也会提高了效率.
- 所以,接收端在这样的情况下就可以先等一会儿再去应答,那么返回的窗口大小就是1M了.窗口越大,吞吐量就越高,传输效率就越大.
延迟应答的策略:
- 进行数量限制:每隔N个包就应答一次.(一般取2)
- 时间限制:超过最大的延迟时间就进行应答一次.(超时时间一般是200ms)
捎带应答
目的:提高数据的传输效率.
在延迟应答的基础上,将数据的确认报文ACK和响应报文一起返回给发送端.
比如:在4次挥手中,如果将对端的确认报文和关闭连接的消息同时发送回去.那么也会提高效率.
~~~~~~~~~~~