TCP粘包、服务器TIME-WAIT过多的问题

一、粘包

TCP是基于字节流传输的,只维护发送出去多少,确认了多少,没有维护消息与消息之间的边界,因而可能导致粘包和拆包问题。

粘包问题分为两种:

  1. 发送方产生粘包

    采用 TCP 协议传输数据的客户端与服务器经常是保持一个长连接的状态,双方在连接不断开的情况下,可以一直传输数据。(一次连接发一次数据不存在粘包)
    但当发送的数据包过于小,那么 TCP 协议默认的会将这些较小的数据包进行合并发送(缓冲区数据发送堆压);(如果过大,取的时候纷乱了,就是拆包。)
    这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。

  2. 接收方产生粘包

    接收方采用 TCP 协议接收数据时的过程是这样的:数据到运输层,TCP 协议处理是将其放置接收缓冲区,然后由应用层来主动获取);这时会出现一个问题,应用层程序不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)(同理拆包也会发生)

tips:

TCP的短连接一般只会在 client/server间传递一次读写操作,然后任一方都可以直接进行关闭连接,而长连接则是不关闭,后续独写继续使用。HTTP的长连接和短连接本质上还是TCP长连接和短连接。具体的应用场景里,应用层采用的连接方式不同。

二、怎么解决粘包问题

  1. 接收端接受包的收采用定长的方式接受,这样每次拿出的数据都是确定一个包的长度;
  2. 在包头首都添加数据包的长度
  3. 在包之间添加特殊符号作为分割。

如果使用 netty 的话,就有专门的编码器和解码器解决拆包和粘包问题了。

tips:

UDP 没有粘包问题,但是有丢包和乱序。不完整的包是不会有的,收到的都是完全正确的包。传送的数据单位协议是 UDP
报文或用户数据报,发送的时候既不合并,也不拆分。

三、服务端能发起四次挥手吗

  • 答案是可以的,服务端先发起关闭请求,那服务端就先发出FIN,然后进入TIME-WAIT状态,但是客户端没有close,还一直处在CLOSE-WAIT状态;
  • 如果客户端继续发送数据,那么因为服务端已经关闭了,所以过段时间操作系统就会强制关闭客户端。

(当服务器 close一个连接时,若 client端接着发数据。根据TCP协议的规定,会收到一个RST(就是首部的RST标志位,表示这次的连接不能用了,需要重新建立连接)响应, client再往这个服务器发送数据时,系统会发出一个 SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了)

四、如果TIME-WAIT状态过多会怎么样?如何解决

作为服务器,短时间内主动关闭的连接比较多,就会造成服务器上出现大量的TIME_WAIT连接要等2MSL时间,严重消耗着服务器的资源;(但是在Windows下似乎默认为4分钟就不再等了?)

作为客户端,短时间内大量的短连接,会大量消耗Client机器的端口,毕竟端口只有65535个,端口被耗尽了,后续就无法再发起新的连接了。

这个情况会出现的场景具体是这样的:

高并发短连接的TCP服务器上,当服务器处理完请求后立刻按照主动正常关闭连接。
这个场景下,会出现大量socket处于TIMEWAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
比如,取一个web页面,1秒钟的http短连接处理完业务,在关闭连接之后,这个业务用过的端口会停留在TIMEWAIT状态几分钟,而这几分钟,其他HTTP请求来临的时候是无法占用此端口的。单用这个业务计算服务器的利用率会发现,服务器干正经事的时间和端口(资源)被挂着无法被使用的时间的比例是 1:几百,服务器资源严重浪费。
(Ref:https://www.cnblogs.com/menghuanbiao/p/5212925.html)

对于服务端,TIME-WAIT状态过多的解决方法:

  • 可以通过调整内核参数解决:内核协议栈代码中关于这个TIMEWAIT的超时时间参数,重编内核,让它缩短超时时间,加快回收
  • 也可以选择分机器,让多台机器来抗这些高并发的短请求。(成本较高)

猜你喜欢

转载自blog.csdn.net/weixin_42092787/article/details/107684816