Skip to content
本页目录

TCP 和 UDP

TCP 和 UDP

TCP 对比 UDP 的区别总结

  • 1、TCP 是面向字节流————UDP 是面向报文的,UDP 没有拥塞控制,因此网络出现拥塞也不会使源主机的发送速率降低(对实时应用很有用,如实时聊天、实时视频通话等)。
  • 2、TCP 是面向连接的(如打电话需要先拨号建立连接)————UDP 是无连接的,即发送数据前不需要建立连接。
  • 3、TCP 提供可靠服务。即通过 TCP 连接传送的数据无差错、不丢失、不重复,且按发送顺序到达————UDP 尽最大努力交付,即不保证可靠交付。
  • 4、每一条 TCP 连接都只能是点到点的————UDP 支持一对多、一对一、多对一、多对多的交互通信。
  • 5、TCP 首部开销大 20 字节————UDP 首部开销小 8 字节。
  • 6、TCP 通信信道是全双工的可靠信道————UDP 则是不可靠信道。

UDP 应用场景:

  • 1.面向数据报方式
  • 2.网络数据大多为短消息
  • 3.拥有大量客户端——Client
  • 4.对数据安全性无特殊要求
  • 5.网络负担非常重,但对响应速度要求高

三次握手 🤝

  • 三次握手其实就是指建立一个 TCP 连接时,需要客户端和服务器总共发送 3 个包。

  • 进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。

  • 实质上其实就是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。

进行三次握手

  • 1、第一次握手:客户端向服务端发送一个 SYN 报文,并同时指定一个 初始化序列号(后面会说到这个序列号的用处),客户端发完这个 SYN 报文后就处于 SYN_SEND 状态。首部的同步位 SYN=1,初始序号 seq=x,SYN=1 的报文段不能携带数据,但要消耗掉一个序号。

  • 2、第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。在确认报文段中 SYN=1,ACK=1,确认号 ack=x+1,初始序号 seq=y。

  • 3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。

确认报文段 ACK=1,确认号 ack=y+1,序号 seq=x+1(初始为 seq=x,第二个报文段所以要+1),ACK 报文段可以携带数据,不携带数据则不消耗序号。 发送第一个 SYN 的一端将执行主动打开(active open),接收这个 SYN 并发回下一个 SYN 的另一端执行被动打开(passive open)。

为什么需要三次握手,两次不行吗?

  • 上面已经讲到过进行三次握手的目的就是为了确定双方的接收和发送能力是否正常。

  • 第一次握手:客户端发送网络包(客户端进入 SYN_SEND——半连接状态),服务端如果收到了(服务端进入 SYN_RCVD——半连接状态),服务端就能确定客户端的发送能力和服务端的接收能力是正常的。

  • 第二次握手:服务端发送网络包,客户端如果收到了(客户端进入 estalished 状态——已建立连接的),客户端就能确定自己的发送和接收能力、服务端的接收和发送能力是正常的。(这时服务器还不能确定客户端的接收能力是正常的,所以需要第三次握手。)

  • 第三次握手:客户端发送网络包,服务端收到了(服务端进入 estalished 状态——已建立连接的)。这样就能确定客户端服务端都有发送和接收的能力了。

如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。

什么是半连接队列

  • 服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。

  • 当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。

  • 这里在补充一点关于 SYN-ACK 重传次数的问题:服务器发送完 SYN-ACK 包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…

ISN(Initial Sequence Number)是固定的吗?

  • 当一端为建立连接而发送它的 SYN 的时候,会为此次连接选择一个初始序号(ISN),ISN 会随时间变化,因此每个连接都会有一个不同的 ISN。
  • ISN 的存在可以防止在网络中被延迟的数据在之后又到达服务器而导致的服务器的处理错误。

三次握手可以携带数据吗?

  • 1、结论是第一次和第二次握手的时候不能携带数据,第三次握手可以携带数据。
  • 2、第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。
  • 3、而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。

SYN 攻击是什么?

SYN 攻击就是客户端(Client)在短时间内用大量伪造的不存在的 IP 地址向服务端(Server)不断的发送 SYN 包,服务端(Server)则需要回复确认包,并等待客户端(Client)确认,由于这些都是伪造的 IP 地址,所以根本就得不到客户端的确认,服务端就一直重传直至超时。由于这些伪造的 SYN 包长时间占用着半连接队列,导致正常的 SYN 请求因为队列已满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

常见的几种防御 SYN 攻击的方法有一下几种:

  • 1、缩短超时时间(SYN Timeout)
  • 2、增加最大半连接队列的容量
  • 3、过滤网关防护
  • 4、SYN cookies 技术

四次挥手 👋

建立一个连接需要三次握手,而终止一个连接需要经过四次挥手。这是由于 TCP 的半关闭状态(half-close)决定的。TCP 提供了连接的双方在发送了 FIN 报文结束了自己的发送后还有接收对方数据的能力。刚开始双方都处于 ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下:

  • 1、第一次挥手:客户端发送一个 FIN=1 报文,报文中指定一个序列号 seq=u,客户端进入 FIN_WAIT1(终止等待一状态)。主动关闭 TCP 连接并停止发送数据。等待服务端的确认。

  • 2、第二次挥手:服务端收到连接释放报文段后即发出确认报文段(ACK=1,确认号 ack=u+1,序号 seq=v),服务端进入 CLOSE_WAIT(关闭等待)状态,此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入 FIN_WAIT2(终止等待二状态),等待服务端发出的连接释放报文段。

  • 3、第三次挥手:如果服务端没有要向客户端发送的数据了,也想要断开连接的话。服务端就会发出连接释放报文段(FIN=1,ACK=1,序号 seq=w,确认号 ack=u+1),服务端进入LAST_ACK(最后确认)状态,等待客户端的确认。

  • 4、第四次挥手:客户端收到服务端的 FIN 报文后,也会发送一个 ACK 确认报文然后进入 TIME_WAIT(2MSL 等待状态)。服务端收到 ACK 报文后就会进入 CLOSED(关闭状态)。

挥手为什么需要四次?

注意

因为建立连接的时候服务端收到客户端发送的 SYN 连接请求报文后,可以同时发送 SYN + ACK 报文给客户端的。但是在断开连接的时候,服务端收到 FIN 报文后很可能不会立即关闭 SOCKET 连接,因为还有数据要传,必须等所有数据发送完后才能断开连接。所以服务端就只能先发送一个 ACK 报文来告诉客户端,你发的 FIN 报文我收到了,等我发完数据后再给你发送 FIN 报文。

为什么会有 2MSL 等待状态?

  • 1、保证客户端发送的最后一个 ACK 报文段能够到达服务端,使服务端能正常关闭。

注意

因为客户端发送的这个 ACK 确认报文有可能丢失,从而导致处在 LAST-ACK 状态的服务器收不到对 FIN-ACK 的确认报文。服务器会超时重传这个 FIN-ACK ,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待 2MSL,而是在发送完 ACK 之后直接释放关闭,一但这个 ACK 丢失的话,服务器就无法正常的进入关闭连接状态。

  • 2、防止“已失效的连接请求报文段”出现在本连接中。

注意

客户端在发送完最后一个 ACK 报文段后,再经过 2MSL,就可以使得本次连接持续的时间内所产生的所有报文段都从网络中消失,保证下一个新的 TCP 连接中不会出现上一个 TCP 连接请求的报文段。

MIT Licensed