TCP和UDP面试考点(握手、挥手、滑动窗口)
TCP
传输控制协议TCP
面向连接的、可靠的、基于字节流的传输层通信协议
将应用层的数据流分割成报文段并发送给目标节点的TCP层
数据包都有序号,对方收到则发送ACK确认,未收到则重传
使用校验和来校验数据在传输过程中是否有误
TCP flag
URG:紧急指针标志
ACK:确认序号标志
PSH:push标志
RST:重置连接标志
SYN:同步序号,用于建立连接过程
FIN:finish标志,用于释放连接
三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。
进行三次握手:

第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于 SYN_SENT 状态。( 首部的同步位SYN=1,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。 )
第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_RCVD 的状态。 ( 在确认报文段中SYN=1,ACK=1,确认号ack=x 1,初始序号seq=y。 )
第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。 ( 确认报文段ACK=1,确认号ack=y 1,序号seq=x 1(初始为seq=x,第二个报文段所以要 1),ACK报文段可以携带数据,不携带数据则不消耗序号。 )
为什么三次,两次不行吗
为了初始化Sequence Number的初始值。
同时也是因为每次握手确定的信息是有限的,第一次握手来说:服务端能够确认客户端的发送能力正常,并且自己的接收能力正常。第二次握手:客户端能够确认服务端的收发能力都正常,并且自己的收发能力也正常,但是此时服务端还不能确认客户端的接收能力是否正常,所以需要第三次握手,客服端在发送一次ACK报文,然后此时服务端能够确认彼此的收发能力都是正常的。
什么是半连接队列
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
关于服务端SYN-ACK重传次数的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
这种情况也就是:Server收到Client端的SYN,回复SYN-ACK的时候未收到ACK确认,Server不断重试直至超时,Linux默认等待63秒才断开连接。重复五次,每次时间翻倍。
针对SYN FLOOD的防护措施
SYN队列满后,通过tcp_syncookies参数回发SYN Cookie,若为正常连接则Client会回发SYN Cookie,直接建立连接
建立连接后,Client发生故障怎么办
保活机制:向对方发送保活探测报文,如果收到相应则继续发送。尝试次数达到保活探测次数仍未收到相应应该中断连接。
SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
预防方法
缩短超时时间(SYN TIMEOUT)
增加最大半连接数
过滤网管防护
SYN cookies技术(前边提到过)
四次挥手
建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。

第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。即发出连接释放报文段(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。即服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号ack=u 1,序号seq=v),服务端进入CLOSE_WAIT(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2(终止等待2)状态,等待服务端发出的连接释放报文段。
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。即服务端没有要向客户端发出的数据,服务端发出连接释放报文段(FIN=1,ACK=1,序号seq=w,确认号ack=u 1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。
第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。即客户端收到服务端的连接释放报文段后,对此发出确认报文段(ACK=1,seq=u 1,ack=w 1),客户端进入TIME_WAIT(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
也就是说主动执行关闭的一方才会进入TIME_WAIT状态
为什么需要四次挥手
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
我的理解:也就是说你单方面开始断开连接,只能说明你不在继续发送数据,我这边数据可能还需要发完才行,所以我先给你一个应答和同步的报文,只有数据发完了才能发送FIN报文。
四次挥手释放连接时,等待2MSL的意义
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
**为了保证客户端发送的最后一个ACK报文段能够到达服务器。**因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
总结就是以下两点
保证客户端发送的最后一个ACK报文段能够到达服务端。
防止“已失效的连接请求报文段”出现在本连接中。(客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。)(避免新旧连接混淆)
服务器出现大量Close_Wait状态原因
**原因:**对方关闭socket连接,我方忙于读或写,没有及时关闭连接。
解决办法: 1:检查代码,特别是释放资源的代码。2:检查配置,特别是处理请求的线程配置。
TCP的滑动窗口
RTT和RTO
RTT:发送一个数据包到收到对应的ACK,所花费的时间
RTO:重传时间间隔
TCP使用滑动窗口做流量控制与乱序重排
1.保证TCP的可靠性
2.保证TCP的流控特性
TCP会话的发送方

发送的数据可以分为以下四类。
已经发送并且已经收到端的回应的
已经发送但还没收到端的回应的
未发送但被端允许发送的
未发送但由于达到的Window的大小不被端允许发送的
第2个状态和第3个状态组成发送方的滑动窗口
TCP会话的接收方

接收方的数据可以分为以下三种状态
已接收并且已经发送回值(ACK)的状态
未接收但是可以接收(准备接收的状态)滑动窗口
未接收并且不能接收的状态
总之通过确认重传机制,只有左边界确认之后滑动窗口才会继续向右移动。
补充
滑动窗口的大小可以根据一定的策略进行动态调整。应用会根据本端处理能力的变化,通过本端TCP滑动窗口大小的控制来实现对端滑动窗口的控制,从而实现流量限制。
UDP补充
UPD的特点
面向非连接
不维护连接状态,支持同时向多个客户端传输相同的消息
数据包头只有8个字节,额外开销较小
吞吐量只受限于数据生成速率、传输速率以及及其性能
尽最大努力交付,不保证可靠交付,不需要维持复杂的链接状态表
面向报文,不对应用程序提交的报文信息进行拆分或者合并
TCP和UDP对比
面向连接VS无连接
可靠性
TCP利用握手和重传机制提供了可靠性保证,UPD可能会丢失不知道到底有没有被接收有序性
TCP利用序列号保证消息报的顺序交付,到达可能无序,但TCP最终会排序。UDP不具备有序性速度
TCP速度较慢,UDP适合对速度敏感的应用,如在线视频媒体,电视广播,多人在线游戏。量级
TCP属于重量级的,头部有20个字节;UDP属于轻量级的,头部有8个字节。
参考【1】猿人谷https://blog.csdn.net/hyg0811/article/details/102366854