TCP协议
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP特点:
- 面向连接
- 点对点,每条连接只能有两个端点
- 可靠交付,保证数据在传输过程中无差错、不丢失、不重复
- 全双工通信,连接两端都能发送和接收信息。
- 面向字节流。
三次握手
三次握手用于建立TCP连接,需要在客户端与服务器之间交换三个TCP报文段。
建立连接的过程:
- 客户端A打算建立TCP连接时,向服务器B发出连接请求报文段,首部中的同步位SYN=1,选择一个初始序号x。此时,A进入【同步已发送状态】表示正尝试建立连接。SYN报文段不能携带数据,需要消耗一个序列号。
- B收到连接请求报文段后,如果同意连接,向A发送确认。在报文段中将同步位SYN和ACK都置1,确认号是x+1,然后选择一个初始序号seq=y,此时B进入【同步已接收状态】。这个报文段也不能携带数据,需要消耗一个序列号。
- A收到B的确认后,还要向B给出确认。确认报文的ACK置1,确认号ack=y+1,序号是x+1。ACK报文段可以携带数据,如果不携带数据则不消耗序号,下一个报文的序号仍是x+1。此时A进入已建立连接状态,当B收到A的确认后,也进入建立连接状态。
为什么要三次握手?
- TCP连接是可靠的,需要确保服务器和客户端都具备接收和发送数据的能力。
- 第一次握手证明客户端具备发送信息的能力,
第二次握手证明服务端具备接收和发送信息的能力
第三次握手证明客户端具备接收信息的能力(只有接收到了信息才会向服务端发送确认信息)
如果是两次就建立连接,服务端无法确认客户端是否具备接收信息的能力; 如果四次或更多的次的话,就造成了重复,前面服务端已经同意了建立连接,并且做好了连接准备,就没必要再次发送同意报文了
- 第一次握手证明客户端具备发送信息的能力,
- 防止因网络堵塞造成服务器忙等,造成资源浪费的情况。
- 如果是两次的话,考虑这样一种情形,客户端第一次发送的连接请求因网络堵塞而没有到达服务器,当到达了超时重传时间后,客户端仍没有收到服务器的确认报文,就会发送第二次连接请求,这时服务端收到了该请求,并发送了确认信息,这时候连接建立;
- 过一段时间后,被网络堵塞的第一次连接请求也到达了服务端,服务器接收后就发送了确认信息,此时建立了连接并为该链接分配了资源,等待客户端发送信息,而客户端并不会处理这个连接,因为它已经通过超时重传建立了连接并处理了自己信息,所以服务端就会忙等,造成了服务端的资源浪费。
四次挥手
通信结束后,通信双方都可释放连接。释放前,A、B双方都处于连接已建立状态,假设A主动关闭TCP连接。
- A把final报文段首部的终止控制位FIN置1,其序号seq=u,此时A进入终止等待1状态。Final报文段即使不携带数据,也要消耗一个序号。
- B收到Final报文段后发出确认,ACK置1,确认号是ack=u+1,序号是v。然后B进入关闭等待状态。此时TCP连接处于半关闭状态,即A没有数据要发送,但是B发送的数据A仍要接收,B到A方向的连接没有关闭。A收到来自B的确认后进入终止等待2状态,等待B发送连接释放报文段。
- 当B发送完数据之后,向A发送Final报文段,FIN置1,ACK置1,序号为w,确认号u+1。此时B进入最后确认状态。
- A收到B的Final报文后,必须对此发出确认,ACK置1,确认号ack=w+1,序号是u+1。然后进入到时间等待状态,必须等待2个MSL【1个MSL后,A发送的确认到达B,再等一个MSL,保证如果B重传了Final,这个Final在1个MSL也能到达A】(MSL是最长报文段寿命,即报文段在网络中存在的最长时间)后,A才进入关闭状态。B收到确认后,也进入关闭连接状态。
为什么需要四次挥手?
第三次挥手的作用是因为B发送完数据后需要通知A,否则A会一直处于等待接收B数据的状态,这样造成了资源浪费。而第四次挥手是A告诉B收到了请求的确认,如果没有这个确认,B不知道A是否收到了自己发出的请求,会一直重传该请求,所以第四次挥手也是必须的。
服务器大量出现close_wait的原因
如果服务器端不执行socket的close()操作,状态就不能由close_wait迁移到last_ack,则系统中会存在很多close_wait状态的连接。
TCP拥塞避免
慢开始
慢开始算法的思路就是,不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。发送方让自己的发送窗口等于拥塞窗口。每经过一个传输轮次,拥塞窗口就增加一倍。为了防止拥塞窗口增长过大,还需要设置慢开始门限。
拥塞避免
当拥塞窗口增大到慢开始门限时,就改为执行拥塞避免算法,此时拥塞窗口加法增大,就是线性增长,使得网络比较不容易堵塞。
无论是在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认,虽然没有收到确认可能是其他原因的分组丢失,但是因为无法判定,所以都当做拥塞来处理),就把慢开始门限设置为出现拥塞时的发送窗口大小的一半。然后把拥塞窗口设置为1,执行慢开始算法。
快重传
快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。立即重传不会出现超时,发送发也不会误以为出现了网络拥塞。
快恢复
快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,知道丢失了个别报文段,于是不启动慢开始(不把拥塞窗口置为1),而是执行快恢复,把慢开始门限设置为当前拥塞窗口的一半,再将拥塞窗口设置为门限值,然后开始执行拥塞避免。
如何保证可靠传输
- TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
- 校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
- TCP 的接收端会丢弃重复的数据。
- 流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
- 拥塞控制: 当网络拥塞时,减少数据的发送。
- 停止等待协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就- 停止发送,等待对方确认。在收到确认后再发下一个分组。 超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
流量控制
TCP采用滑动窗口实现流量控制,以控制发送方发送速率,保证接收方来得及接收。接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
TCP粘包问题
参考-TCP粘包问题
TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。
- 发送方造成的粘包
TCP默认使用Nagle算法(主要作用:减少网络中报文段的数量),而Nagle算法主要做两件事:第一是只有上一个分组得到确认,才会发送下一个分组;第二是收集多个小分组,在一个确认到来时一起发送。
2. 接收方造成的粘包
TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理。TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组。这样一来,如果TCP接收数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 changzeyan@foxmail.com