1.TCP拆包粘包
拆包
拆包发生原因分2种情况:
- 发送的数据大于套接字缓冲区剩余大小。
- 发送的数据大于MTU(最大传输单元)大小。
粘包
因为在TCP通讯协议中TCP是面向流的,包和包之间没有界限。
- 发送端原因导致的粘包,客户端在发送p1包时,先将p1包放入发送缓存,由于Nagle算法判断其发送的可用数据(去头数据)过小等待一小段时间,这时又发送了p2包,系统将p1和p2合成一个大包发送给服务端。服务端读到大包,无法区分p1和p2包。
- 接收端原因导致的粘包,服务端缓存接收到客户端发送的p1包,服务端应用未能及时读取缓存,此时服务端缓存又接收到客户端发送的p2包,服务端应用读取缓存,无法区分p1和p2包。
解决方案
无论拆包还是粘包本质问题都是无法区分包界限,解决包界限的问题主要有以下几种方式:
消息数据的定长,比如定长100字节,不足补空格,接收方收到后解析100字节数据即为完整数据。但这样的做的缺点是浪费了部分存储空间和带宽。
消息数据使用特定分割符区分界限,比如使用换号符号做分割。
把消息数据分成消息头和消息体,消息头带消息的长度,接收方收到后根据消息头中的长度解析数据。
参看文章:https://segmentfault.com/a/1190000015854646
3.TCP三次握手
第一次握手:(SYN=1, ACK=0, seq=x):Client发送SYN标志位1的包到Server,以及初始序号x(保存在包头的序列号seq字段,简称ISN),和ACK标志位为0,并进入SYN_SEND状态,等待Server确认。
第二次握手:(SYN=1, ACK=1, seq=y, ack=x+1):Server发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。Server确认ISN序列号,放到seq域里,同时将确认序号(ack)设置为Client的ISN加1,即x+1。 发送完毕后,Server进入 SYN_RCVD 状态。
第三次握手:(ACK=1,seq=x+1,ack=y+1):Client再次发送确认包(ACK),ACK标志位为1,并且把Server发来ISN的序号字段+1,放在确定字段中发送给对方。
4.TCP四次挥手
第一次挥手(FIN=1,seq=u):Client 想要关闭连接,Client 会发送一个FIN标志位置为1,当前序列号为u的包,表示需要关闭连接了。Client进入 FIN_WAIT_1 状态。
第二次挥手(ACK=1,seq=v,ack=u+1):Server收到Client的FIN包之后,会发送一个确认序号为收到的序列号u+1的包,表明自己接受到了Client关闭连接的请求,但还未准备好关闭连接。Server进入 CLOSE_WAIT 状态,Client进入 FIN_WAIT_2 状态。
第三次挥手(FIN=1,ACK=1,seq=w,ack=u+1):当Server将剩余数据发送完之后,会发送一个自己的FIN包,序列号为u+1。Server进入 LAST_ACK 状态,等待来自Client的最后一个ACK。
第四次挥手(ACK=1,seq=u+1,ack=w+1):Client接收到来自Server端的关闭请求之后,发送最后一个ACK确认包,确认序号设置为收到序号加1。Client进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。Server接收到这个确认包之后,关闭连接,进入CLOSED状态。(Client会等待2MSL之后,没有收到Server的ACK ,就确认Server进入CLOSED状态,自己也关闭进入CLOSED状态。)
5.TCP滑动窗口
6.服务器大量TIME_WAIT
7.TCP协议怎么保证安全性
https://blog.csdn.net/liuchenxia8/article/details/80428157
- 校验和
- 序列号
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
校验和
计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数。将这些整数加起来。并且前面的进位不能丢弃,补在后面,最后取反,得到校验和。
发送方:在发送数据之前计算检验和,并进行校验和的填充。 接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方的进行比对。注意:如果接收方比对校验和与发送方不一致,那么数据一定传输有误。但是如果接收方比对校验和与发送方一致,> 数据不一定传输成功。 确认应答与序列号
序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号。
确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
序列号的作用不仅仅是应答的作用,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据。
超时重传
发送方没有介绍到响应的ACK报文原因可能有两点:
- 数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到。
- 接收方接收到了响应的数据,但是发送的ACK报文响应却由于网络原因丢包了。
TCP在解决这个问题的时候引入了一个新的机制,叫做超时重传机制。简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行ACK应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送ACK应答。
由于TCP传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算的。
连接管理
连接管理就是三次握手与四次挥手的过程
流量控制
接收端在接收到数据后,对其进行处理。如果发送端的发送速度太快,导致接收端的结束缓冲区很快的填充满了。此时如果发送端仍旧发送数据,那么接下来发送的数据都会丢包,继而导致丢包的一系列连锁反应,超时重传呀什么的。而TCP根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制。
在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。
拥塞控制
TCP引入了慢启动的机制,在开始发送数据时,先发送少量的数据探路。探清当前的网络状态如何,再决定多大的速度进行传输。这时候就引入一个叫做拥塞窗口的概念。发送刚开始定义拥塞窗口为 1,每次收到ACK应答,拥塞窗口加 1。在发送数据之前,首先将拥塞窗口与接收端反馈的窗口大小比对,取较小的值作为实际发送的窗口。
拥塞窗口的增长是指数级别的。慢启动的机制只是说明在开始的时候发送的少,发送的慢,但是增长的速度是非常快的。为了控制拥塞窗口的增长,不能使拥塞窗口单纯的加倍,设置一个拥塞窗口的阈值,当拥塞窗口大小超过阈值时,不能再按照指数来增长,而是线性的增长。在慢启动开始的时候,慢启动的阈值等于窗口的最大值,一旦造成网络拥塞,发生超时重传时,慢启动的阈值会为原来的一半(这里的原来指的是发生网络拥塞时拥塞窗口的大小),同时拥塞窗口重置为 1。
