TCP在网络协议(网络协议见这篇文章)中是非常重要的,要说有多重要的话,那就像珍珠奶茶的奶茶一样。
1. 三次握手
TCP在进行数据的传输之前必须先建立连接,建立之后才能进行数据的传输,那么所谓的建立连接是怎么回事呢?来看下其三次握手。
- 客户端发送SYN和seq序列号,SYN为标识位,意思为请求同步,seq是此次包的序列号,序列号是单调递增的,作用是保证传输的可靠性,在丢包的时候能确定丢的是哪个包。
- 服务端收到消息之后,发送确认的信息,包括标识位SYN和ACK(表确认作用)、确认信息ack=客户端发送的seq+1,seq=自己的seq。seq和ack的确认机制知道确认的是哪个包。
- 客户端收到服务端的确认消息(也是请求同步的信息)之后,回复其同步消息,发送ACK=1和ack=服务端的seq+1还有自己的seq(值为第一次的seq+1,要单调递增),此时客户端这边的连接已经完成了。
- 服务端接收到客户端的消息之后,服务端这边的连接也完成,至此三次握手圆满结束,接下来就可以传输数据了。
三次握手的流程并不复杂,概括就是:客户端向服务端发送同步请求,服务端确认并向客户端发送同步请求,客户端确认,连接完成。
但是在这简单的流程中有几个问题需要思考:
- 为什么需要三次握手?
- 服务端有超时重传机制吗?确认包发送之后一段时间没收到响应会重发吗,还是等待客户端重发包。
- 客户端收到服务端的确认消息之后能发送数据吗,即第二次握手完成的时候客户端能向服务端发送数据吗?
上面这些问题是不是除了第一个其他的都没想过?你可能会说,"那肯定啊,谁没事去想这玩意,我学TCP都是为了面试的时候能够把三次握手和四次挥手说出来。"
哼!对于这种想法,我只能说:
不过如果想造火箭,自己总不能是一颗汽车的轮子吧(布加迪威龙除外),所以必要的思考很重要。那来看看这几个问题
-
为什么要三次握手?
答:因为四这个数字不吉利。
开个玩笑,麻烦把砖头收一收。首先我们得理解TCP是双方的连接,也就是说只有确定客户端和服务端的发送和接收都是没问题的这个连接才算完成。那来看下,第一次握手略过,第二次握手也就是客户端接收到服务端的确认消息时,这里证明了两个问题:
- 服务端的确认消息中的ack是自己的seq+1,说明服务端收到了自己刚才发的包并且能够明白。
- 自己收到确认消息说明服务端的发送端正常,自己的接收端正常。
到第二次握手这里已经证明了三个所需条件:客户端的发送和接收正常、服务端的发送正常。还少一个服务端的接收,所以客户端要再发一次给服务端的确认包,让服务端也知道其发送和接收是正常的,所以总共是三次。
-
服务端有超时重传机制吗?
有的,如刚才所说,TCP是双端的协议,服务端是接收方也是发送方,所以是有超时重传的机制。比如说第三次握手客户端向服务端发送消息时由于网络原因丢包了,那么服务端一段时间后没收到消息就会重发。
-
客户端收到服务端的确认消息之后能发送数据吗?
意思就是说,在第二次握手完成后,客户端能不能向服务端发送数据。在回答这个问题之前,我先问一个问题,这时候客户端这边已经确认发送和接收没问题了,现在不能发,什么时候能发呢?所以是可以的,就算丢包也有确认应答和重发机制来保证。
三次握手结束之后,就可以进行数据的传输,这里有长连接和短连接之分。可能放在这里比较陌生,但是另一个协议——HTTP的长连接和短连接应该都知道了,其本质就是TCP的长连接和短连接,而且作用是一样的,短连接在发送一次数据后就进行关闭,长连接则保持直到主动选择关闭分开。
说到分开,让我不由得想起那一年四月,夕阳淌在她的脸上,她用纤细的手指挽起了耳边的秀发,转过头对我说:"我们之间已经没有什么能给对方的了,总要一个人先开口,就像TCP'四次挥手'一样!"
醒醒,程序猿哪里有女朋友。
2. 四次挥手
不知道怎么开头,先给大家看个宝贝吧。
看了这张图都是字母,即便你告诉我这就是四次挥手,但这就像JOJO一样,一开始我是难以接受的。没有关系,鲁迅说过,"四次挥手比起机械的记忆,尝试去理解带来的性价比可能要高得多。"
我们一开始也说过,TCP是双方的协议,所以双方要有沟通,这样才能正确的关闭通道。而TCP的沟通,是这样的:
客户端:"我这边数据发完了,我要把我这边的发送通道关了,你看下你那边有没有什么问题。"
服务端:"嗯,我数据接收完了,你关吧,我把我这边的接收通道也关了。"
okay,这样客户端关闭了发送通道,服务端关闭了接收通道(注意,只能由发送通道发起聊天)。过了一段时间后,服务端这边的数据也都传输完了,他也想关闭了。
服务端:"我这边的数据也发完了,我这边把发送通道关了就下班了,你还有什么问题吗?"
客户端:"我这边也接收完了,你关吧,我也把这边的接收通道关了。等下下班后一起去修车吗?"
此时客户端还不能直接关完走人,因为他不知道修车地址啊(可恶)。说错了,是他担心服务端没收到他的消息,那需要等他个2MSL吧,如果服务端真的没收到会重新发信息过来的,到时候我再发一次就行。
到这里再回过头来看上面那张图。emem,是不是完全搞懂了。
(不理解再慢慢看看)个人觉得图中最重要的应该是TIME_WAIT状态,以及为什么要等2MSL,顺便说下MSL是报文单位,不想懂可以理解为另一种意义的秒。
所以以后再被问为什么要四次挥手?你就说为了一起修车(不是)。
3. TCP是如何保证可靠性的
当我们被问到TCP和UDP的区别时,我们总会回答:"TCP是可靠的,而UDP是不可靠的。"但TCP为什么是可靠的,是怎么保证其可靠性的可能就没那么多人知道了。
- 校验和
- 序号和确认应答:
- 超时重传
- TCP不处理重复的包
- ARQ协议
- 流量控制
- 拥塞控制
上面这些就是TCP可靠性的基石,来看下这些基石长什么样。
-
校验和
将头部和数据通过一个算法得到一个结果,这个结果就是校验和。校验和是防止包在传输的过程中被修改,接收端接收到包也会通过特定的算法来检测校验和是否能对上。
-
序号和确认应答
这在上方三次握手的时候也有涉及到,意思就是在发送方每次发送的包都是有序号的,如果包丢了,就要重新发下这个序号对应的包,而确认应答机制可以做到让发送端知道该重发的是哪个包。
如上图,在传输的过程中,如果中途丢了一个包,例如上图的11-20的包,那么接收方就会不断的确认1-10的包,即便收到21-30的包,发送方收到三次这样的确认之后便判定包已丢失进行重发。
-
超时重传
这就没什么好说的,无论是服务端还是客户端在发送之后都会启动一个定时器,一段时间之后没收到确认定时器就会触发重发。
-
TCP不处理重复的包
假设现在网络很慢,客户端发了消息之后一直没收到回复,就会重发,两次或者更多次,而且发的是同一个序号的包,那么这时服务端可能先收到一个包,进行处理后发送确认消息,之后又收到了同一个序号的包,此时便不做处理,直接丢弃,对于后面来的相同序号的包也执行相同的操作。
-
连续ARQ协议
TCP采用的是连续ARQ协议,大致的意思就是说,有数据不马上发,等待凑齐一定数量或者到了最大等待时间再发,凑齐一定的数量称为一组,而连续ARQ协议就是说不用等待确认消息再发下一组,可以连续发多组。(ARQ协议还有另外一种,有兴趣的可以自己了解下)
-
流量控制
在介绍流量控制之前,先提出一个问题:服务端有没有可能出现接收不过来的情况?肯定有,不然我接下来的内容怎么写。
那么如果出现这样的情况,会有怎么样的后果呢?
服务端处理不过来,给客户端的响应就会变慢,而客户端收不到响应触发超时重传,哦吼,服务端本来就忙不过来,你还一直施加压力,这不是让服务端往死路逼嘛。
而流量控制,就是为了解决这种问题的。那么流量控制究竟做了什么呢?
首先,发送方和接收方双发之间都维护了一个窗口,叫滑动窗口。接收方的窗口规定了还能接收多少数据,而发送方的窗口则规定了还能发送多少数据。接收方在回复确认信息的时候会将其能接收的大小发给发送方,发送方的窗口大小则取最小值Math.min{接收窗口大小,网络窗口大小(下个节点讲)}。如果接收窗口的大小为0,那么发送方将不再传输数据,而是采用发送探测包的形式检测是否能继续发送数据。
-
拥塞控制
假设有这样一个场景:
客户端发出了一个包,由于网络原因,导致了重发,但还是得不到响应,所以就不断的重发,在这停住,然后把视野抽出来,看到有几亿个客户端如此,继续放送,现在会发生什么呢?
原本网络由于某些原因可能只有一点堵塞,但是由于n个客户端进行了多次的重发操作,导致一下子就拥堵了起来,拥堵又会导致更多的客户端超时而重发,从而进入一个恶性循环,这,自然是不行的。
那咋办呢?还能咋办,遇事不决,限流解决。限流要限多少呢?无论定多少都感觉会错,那从1开始逐渐逐渐往上升,总能有一个是对的吧?好想法!!!于是便有了慢启动算法,见下图。
(此图片来源网络,若有侵权联系我删除)首先,发送方不是一下子发送所有数据,而是从小事做起,先发一个,如果正常那么发两倍,如此如此,直到到了一个阈值,如上图中的16,此时不能再两倍发了(因为再这样很容易就超时),所以+1发,就这样一直到到超时。如果发生了超时,阈值调整为发生超时时的一半,并且发送发从1开始按照上方的算法继续走。这就是慢启动算法。
注意发送方能发的包大小还得看另一个参数——接收方的接收窗口大小,见上方流量控制的介绍。发送方的发送数据大小=min{接收方接收窗口,慢启动算法网络窗口},也就是两个的最小值。
有了上面这些,还有谁能质疑TCP的可靠性呢?
如果觉得文章对你有帮忙,希望关注没事。[双手合十]
参考:
https://blog.csdn.net/sinat_36629696/article/details/80740678