赞
踩
TCP和UDP都是传输层的协议.
TCP的特点是有连接,可靠性,面向字节流,全双工.
正常情况下,TCP连接要进行三次握手,断开连接要进行四次挥手.
TCP连接及断开连接问题,是面试中常考的问题,我们需要画图解释.
如下图,是客户端与服务器建立连接的流程图.
图中我们要注意两个状态
A. 服务器的第二个状态,LISTEN,代表服务器服务器已经做好连接的准备,可随时与客户端建立连接.
B. 客户端与服务器的最后一个状态都是ESTABLISHED,代表此次连接建立成功,可以正常通信.
如果面试题中,要求描述三次握手的过程,我们只需画出下图.
三次握手的本质是,各自要向对方发起一次建立连接的请求,并在接收到对方的请求时立即返回一个ACK.
有同学会有疑问了,为什么一共有四次交互,却是三次握手呢?
由于第2,3步之间时间间隔很短,可以合并.所以协议将这两步封装到一起.所以成了三次握手.也可以节省开销.
那两次握手可不可以呢?答案是不行.为啥呢?
其实,三次握手还有一个意义,就是验证客户端和服务器的收发功能都没问题.
如下图,当客户端发送请求时,只有服务器返回ack了,才确定客户端的发送能力没问题,服务器也保证自己的接收能力没问题.
而只有当客户端在接收请求后返回ack时,才保证了服务器的发送能力没问题,客户端的接受能力没问题.
之后才可以进行数据的发送.
如下图,是断开连接四次挥手的具体流程.
这里有两个重要的状态
面试中如问到这个问题,画出下图即可.
那么这里第2,3步为什么不能合并呢?由于服务器端在接收到断开请求后,还能做一些事情(根据代码而定),所以第2,3步之间有一定的时间差,不能进行封装.
确认应答是实现TCP可靠性的最核心机制.
如果发送端迟迟没有收到接收端返回的ACK,就无法确认数据是否被正确传输.
TCP引入了重传机制,程序员可以根据具体情况,设置一个时间域值,在发送端发送数据之后,开始计时,一旦超过这个时间阈值,无论数据是否丢失,都视为数据丢失,发送端重新传送数据.
但这里会出现一个问题,一个消息传的很慢,超过时间阈值之后仍未传达.此时,发送端重新发送数据,那么这同一个消息可能会发送了两次.
如何解决这个问题呢?TCP的接收端有接收缓冲区,会以优先级队列的方式,将消息进行排序,将相同的消息进行去重.
由于每发送一条消息,就要返回一个ACK,之后才可以发送下一条消息,很消耗时间.因而,TCP设置了滑动窗口机制.
如下图,一次发送多条消息,之后,等待这一组数据的ACK.节省了很多时间
把不需要等待就能直接发送的数据的最大的量称为窗口大小.
需要注意的点是,在客户端等待一组数据的ACK时,并不需要等待所有ACK都到,再集中发下一组数据,而是到一部分就可以发下一部分.例如客户端收到1001的ACK,就代表1-1000之间的ACK已经全部被确认,就可以发送下一个1000数据报即(3001-4000)了.
若有1-1000出现丢包情况,则只需重传1-1000的数据报即可,之后在接收缓冲区进行重新排队.
滑动窗口有几个问题.
流量控制和拥塞控制共同决定发送方窗口大小.
滑动窗口有个问题,就是一开始的时候,并不知道窗口大小,若此时贸然发送大量数据,可能加重网络拥塞.
因而TCP引入拥塞控制,引用慢启动机制,先发送少量数据,确认一下当前网络的拥堵状态,在确定之后的窗口大小.
如下图,为拥塞窗口变化图.
延时应答也是提升效率的机制.是在收到数据后,不要立即返回ACK,而是延时以下,处理一下接受缓冲区里的数据,以便下一次的发送窗口能更大一些.
由于上面的延时应答机制,客户端发送数据,服务器并不会立即返回ACK,而是会延迟一下.而此时,若到了服务器发送下一条消息的时机,服务器可把上次的ACK捎带上,一同发送给发送方.
TCP面向字节流,接收缓冲区会把收到的数据放在一起,从而难以区分读到那算是完整的一条数据.这种情况称为粘包问题.
解决办法