TCP概述
TCP是一种面向连接的协议,在发送数据前通信双方必须在彼此间建立一条连接
所谓的连接其实就是客户端和服务器的内存里保存一份关于对方的信息,如IP地址、端口
TCP是一种字节流,它会处理IP层的丢包、重复以及错误问题
在建立连接的过程中,双方交换的一些参数可以放到TCP的头部
总结 :TCP提供了一种可靠、面向连接、字节流、传输层的服务,采用三次握手建立一个连接,四次挥手关闭一个连接
TCP报文格式
源端口、目的端口:发送方和接收方的端口号
序号:TCP连接中的字节流都有编号。如果101开始,传送了100个字节,那么下次就是从201开始
确认序号:接送方发给发送方下次需要的字节序号
首部长度:就是TCP首部的长度,记录了TCP报文数据到TCP报文段开始的距离
保留:留待以后使用
URG:紧急字段 1-代表有紧急数据 0-代表没有
ACK:在TCP报文段中,字段ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1
PSH:当两个应用在进行交互时,如果想要立马得到对方的回复就PSH设置为1
RST:RST为1时代表需要重新建立连接
SYN:在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1;
FIN:用来释放连接;当FIN=1时代表终止连接
窗口大小:用来进行流量控制
校验和:对整个TCP报文段进行校验和计算,由目标端进行校验
紧急指针:记录一个偏移量,指向紧急数据的最后一位(也可以是紧急数据的下一位,两者都是标准),在读取到紧急指针所指向的位置之前,TCP的接受进程都处于紧急状态,当读取到紧急数据后一位时,回复到正常状态。
三次握手
四次挥手
流量控制
如果发送者发送数据过快,接收者来不及接收,那么就会有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。流量控制根本目的是防止分组丢失,它是构成TCP可靠性的一方面
流量控制主要是用滑动窗口实现
发送窗口 = 1,接收窗口 = 1 停止等待
发送窗口 > 1,接收窗口 = 1 回退N帧协议
发送窗口 > 1,接收窗口 > 1 选择重传协议
停止协议
发送方必须受到接收方返回回来的ACK数据包才能继续发送下一个不然就超时重传
性能较差一次只能发送一个
没有问题
出现问题
回退N帧协议
发送窗口
新的分组落入发送缓冲区,发送->前沿移动
超时重发机制让发送端将发送窗口中的所有方法发送出去
接收窗口
收到乱序分组,没有落入到接收窗口范围,抛弃
发送老分组的确认,累计确认
选择重传协议
发送窗口
新的分组落入发送区域缓冲区范围,发送->前沿移动
超时重发机制让发送端将超时的分组重新发送出去
来了乱序分组的确认->后沿不向前移动->新的分组无法落入发送缓冲区的范围
接收窗口
收到乱序分组,落入到接收窗口范围,接收
收到该分组的确认,单独确认
拥塞控制
在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞控制。拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器以及与降低网络传输有关的因素。相反,流量控制往往是控制点对点的通信量,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便于接收方来得及接收
慢开始
拥塞窗口和接收窗口共同决定的发送窗口
当主机开始发送数据时,如果把大量数据字节注入到网络中,那么会引起网络阻塞,因为现在不知道网络的负荷情况
所有较好的办法就是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd初始值为1,每经过一个传播轮次,cwnd加倍
如果不对cwnd限制马上就会导致cwnd膨胀所有就有一个慢启动阈值ssthresh
如果cwnd > ssthresh 就用拥塞避免
如果cwnd < ssthresh 就用慢开始
拥塞避免
拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送放的 cwnd 加 1
不论是慢开始还是拥塞避免只要网络出现拥塞(没有按时到达)时,就把ssthresh的值置为出现拥塞时的拥塞窗口的一半(但不能小于2),以及cwnd置为1,进行慢开始。 目的是迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
快重传与快恢复
快重传详情看 重传机制-快速重传
快速恢复
当发送方连续收到三个重复确认,就执行"乘法减小"算法,把慢开始门限ssthresh减半。然后立即重传丢失报文段,并将cwnd设置为新的ssthresh然后进行拥塞避免算法
重传机制
超时重传
RTT:往返时间(发送方发给服务方然后发送方收到服务方应答的时间)
RTO:超时重传时间
在发送数据包时就开启一个定时器,如果定时器超时了还没有收到ACK就发起重传,如果收到了ACK就发送数据包再重置定时器
超时重传发生情况:
1、数据包丢失
2、确认应答丢失
RTO时间设置
1、RTO 较大时:重发就慢,丢了过后很久才发,效率低
2、RTO 较小时:可能没有丢失,但是RTO到了就重发,导致网络拥塞,导致更多的超时,导致更多的重发
所有RTO应略大于RTT
快速重传
快速重传的工作方式是当收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
为什么是三次冗余ACK
通过大量经验表明三次比较合适
为什么不进行两次握手
1、确认双方的接收与发送能力是否正常
第一次握手:客户端发送网络包,服务端收到了。服务端:客户端的发送能力、服务端的接收能力正常
第二次握手:服务端发包,客户端收到了。客户端:服务的发送能力、服务端的接收能力、客户端的接收能力、发送能力正常
第三次握手:客户端发包,服务端收到了。服务端:服务端的发送能力,客户端的接收能力正常
2、防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误
如果客户端发出连接请求,因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后释放连接,客户端发出了两个连接请求报文段,其中一个丢失了,第二个到达了服务端,但是第一个丢失的报文段有可能只是由于某些网络节点长时间滞留了,延误到连接释放以后的某个节点,此时服务端认为是客户端又发出一次请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认就建立了新的连接,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源
为什么关闭连接时客户端会等待2MSL
MSL:报文段最大存活时间
1、为了保证客户端发送的最后一个ACK报文能够到达服务器,因为在这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且重启2MSL计时器
2、防止类似与”三次握手中提到了"已经失效的请求报文段"出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中就不会出现旧连接的请求报文
建立连接后客户端出现故障怎么办
TCP设有一个保活计时器,当客户端出现故障时,服务器不能一直等待下去,白白浪费资源。服务器每收到一个客户端的请求后都会复位这个计时器,时间通常设置为2小时,若超时后还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75s发送一次。若一连发送10个探测报文仍然没有反应,服务器就认为客户端出了故障,接着就关闭连接
TCP黏包与粘包问题
什么是黏包与粘包
TCP传输的是字节流,所谓流,就是发送的是一连串的数据,没有界限。TCP底层不会解析具体的数据内容,它会根据缓冲区的实际情况进行包的划分(发送和接收),由此会导致上层业务的一个完整的包被拆分成多个包进行发送(“拆包”),或者多个小包被封装成一个大的数据包进行发送(“粘包”),这就是所谓的TCP的拆包和粘包问题。
如何解决
1、固定应用层发送消息的长度,如果不够就补充空格
2、在包尾添加回车换行符进行分割
3、将消息分为消息头与消息体,消息头中包含长度
4、更复杂的应用层协议