前言

web前端常考TCP与UDP的知识解析,力争基础达标,往后深入的点分开补充~

关键词:TCP/UDP、三次握手、四次挥手、流量控制、拥塞控制、TCP粘包

TCP和UDP

  1. tcp是面向链接的 udp是无连接的即发送数据前不需要建立连接
  2. tcp提供可靠的服务,也就是说通过tcp连接发送的数据,无差错,不丢失,不重复,且按序到达,udp尽最大的努力交付,即不保证可靠交付。并且因为tcp可靠,面向连接,不会丢失数据因此适合大数据量的交换
  3. tcp是面向字节流,udp面向报文,并且网络出现拥塞不会使得发送速率降低(因此会产生丢包,对实时的应用比如ip电话和视频会议等)
  4. tcp只能是一对一的,udp支持1对1 1对多
  5. tcp的首部较大为20字节 udp只有8字节
  6. tcp是面向连接的可靠性传输,udp是不可靠的

常见使用场景

UDP:

  • 直播
  • 游戏

TCP三次握手

建立连接前,客户端和服务端需要通过握手来确认对方

  • 客户端发送SYN同步序列编号请求,进入SYN_SEND状态,等待确认
  • 服务端接收并确认SYN包之后发送SYN+ACK包,进入SYN_RECV状态
  • 客户端接收SYN+ACK包之后,发送ACK包,双方进入ESTABLISHED状态

为什么采用三次握手?

举例:已失效的连接请求报文段

  • 如果客户端发送请求报文但由于网络问题导致报文失效,服务端接收到请求后就会发送确认报文表示同意连接。此时如果是两次握手,那么此时服务端已经建立了新的连接,但由于这个请求是失效的,客户端并没有建立连接,服务端就会浪费很多资源。如果是三次握手,那么此时服务端收不到确认连接的信息,就知道客户端没有建立连接。这就是三次握手的作用。

    TCP有六种标识SYN建立连接,ACK确认,PSH传送,FIN结束,RST重置,URG紧急

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

  • 第一次第二次握手不能携带数据,因为第一次握手和第二次握手服务端还没有建立连接,此时发送数据会让服务器受到攻击。
  • 第三次握手服务器已经处于ESTABLISHED状态,对于客户端来说已经建立了连接,并且也知道服务器的接收发送能力是正常的了,所以能携带数据。

四次挥手

为了确保数据能完成传输

  • 客户端—FIN—>服务端,FIN——WAIT
  • 服务端—ACK—>客户端,CLOSE——WAIT
  • 服务端—ACK,FIN—>客户端,LAST——ACK
  • 客户端—ACK—>服务端,CLOSED

为什么连接的时候是三次握手,关闭的时候是四次挥手?

  • 服务端接收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。
  • 但是在关闭连接的时候,当服务端收到FIN报文的时候 ,很可能并不会立刻关闭连接,所以只能先回复一个ACK报文,告诉客户端,你发的FIN报文收到了,只有等服务器所有的报文发送完了才能发送FIN报文,因此不能一起发送,故需要四次挥手。

拥塞控制

网络拥塞(congestion)是指在分组交换网络中传送分组的数目太多时,由于存储转发节点的资源有限而造成网络传输性能下降的情况。当网络发生拥塞时,一般会出现数据丢失,时延增加,吞吐量下降,严重时甚至会导致“拥塞崩溃”(congestion collapse)。通常情况下,当网络中负载过度增加致使网络性能下降时,就会发生网络拥塞。下图则描述了在有无拥塞控制的干预下,网络吞吐量随输入负载的增加的变化情况。


通过以上的描述,我们大概可以得到以下信息:

  • 网络拥塞往往是由于对资源的请求超出了存储转发节点的能力而导致的。
  • 网络拥塞可能会导致数据丢失,时延增加,吞吐量下降等问题。
  • 若出现拥塞而不进行控制,有可能会使整个网络情况恶化,甚至网络吞吐降为0。
  • 网络的拥塞状况与当前网络负载是密切相关的。

拥塞控制算法

  1. 慢启动
  2. 拥塞避免
  3. 快重传
  4. 快恢复

流量控制

如果发送方的数据发送过快,接收者来不及接收,就有分组丢失。为了避免分组丢失,控制发送者的发送速度,使得接收者来得及接收,这就是流量控制。

流量控制的根本目的是防止分组丢失,它是构成TCP可靠性的一方面

实现流量控制

滑动窗口协议(连续ARQ协议)实现。它保证了分组无差错,有序接收,也实现了流量控制。

主要的方式是 接收方返回的ack包会包含自己接收窗口的大小,并且利用大小来控制发送方的数据发送

流量控制引发的死锁?怎么避免死锁发生?(没看明白)

当发送者收到了一个窗口为0的应答,发送者便停止发送,等待接收者的下一个应答。但是如果这个窗口不为0的应答在传输过程丢失,发送者一直等待下去,而接收者以为发送者已经收到该应答,等待接收新数据,这样双方就相互等待,从而产生死锁。为了避免流量控制引发的死锁,TCP使用了持续计时器。每当发送者收到一个零窗口的应答后就启动该计时器。时间一到便主动发送报文询问接收者的窗口大小。若接收者仍然返回零窗口,则重置该计时器继续等待;若窗口不为0,则表示应答报文丢失了,此时重置发送窗口后开始发送,这样就避免了死锁的产生。

拥塞控制和流量控制的区别

拥塞控制就是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况。常用的方法是:慢开始,拥塞避免,快重传,快恢复。

流量控制就是作用于接收者的,它是控制发送者的发送速度从而使得接收者来得及接收,防止分组丢失

TCP粘包

什么是TCP粘包

现在假设客户端连续发了两个数据包给服务端,用pack1和pack2来表示,那么就有以下几种情况:

  1. 接收端正常收到了两个数据包,没有发生异常
  2. 接收端只收到一个数据包,因为TCP不会丢包所以这个数据包包含了发送端发送的两个数据包,这就是粘包。服务端不知道怎么划分这两个数据包所以很难处理。
  3. 接收端收到两个数据包,但它们都不完整。这种情况下可能是pack1丢了一点到pack2,也有可能是pack2丢了一点到pack1,此时发生了粘包拆包

为什么会发生粘包拆包

原因如下:

  1. 本身套接字缓冲区大小不足,一次写入的数据多了,就发生了拆包
  2. 本身套接字缓冲区过大,多次写入数据,就发生了粘包
  3. TCP连接复用,本来单独的连接中双方规定好了数据格式,但是因为复用导致多个进程以及不同的数据格式传输,就造成了粘包
  4. 接收方没及时接收数据,就发生了粘包

解决方法

解决方法就是处理这个边界问题。

  1. 尾部标识法:通过协商的尾部标记,比如\n\t\r等来说明这是边界
  2. 头部标记法:不是不知道长度吗?直接在TCP头部加上标识数据长度
  3. 定长发送法:发送端封装数据包为指定长度发送