客户端连接已建立,但服务端却说没连上?一次TCP三次握手背后的真相
发布于2025-05-31 00:18:09,更新于2025-05-31 21:44:55,标签:java devops tcp 文章会持续修订,转载请注明来源地址:https://meethigher.top/blog该问题是偶然发现的,起源于内网穿透在高并发时,DataProxyServer返回给User数据时,偶现数据丢失。 · Issue #8 · meethigher/tcp-reverse-proxy。
复现步骤
- 开启TunnelServer
- 开启TunnelClient
- 开启自定义BackendServer。简单实现一个长连接TcpServer,连接进来之后,返回一段字符串即可。
BackendServer源码如下
1 | import io.vertx.core.Vertx; |
客户端与TunnelServer建立2000个长连接,会出现一种情况:客户端显示连接已经处于ESTABLISHED,但是服务端并没有该连接。
那简单,tcp抓包。发现客户端和服务端的三次握手均成功了。
那么,就得去了解三次握手建立连接的这个过程了。
对于客户端来说,当三次握手后,连接就会进入ESTABLISHED。
对于服务端来说,当三次握手后,操作系统内核会将连接放入到全连接队列AcceptQueue,此时连接会进入ESTABLISHED。若放入失败,则丢弃该连接或者发送RST。如果accept()
过慢、连接建立过快。就会出现连接丢失的问题。
解决办法如下
- 调大AcceptQueue的参数值。临时立即生效
sysctl -w net.core.somaxconn=5000
,重启会失效。 - 设置若超过AcceptQueue最大值,则向客户端发送RST中止连接。临时立即生效
sysctl -w net.ipv4.tcp_abort_on_overflow=1
,重启会失效。
但是第二个方法有点鸡肋,即使AcceptQueue满了,也不一定会触发。因此保险起见,还是调大AcceptQueue比较好。
打赏