You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TCP连接卡在SYN_SENT状态的原因及解决方法咨询

问题本质

高频串行HTTP短连接轮询(10ms/1ms间隔)时出现SYN_SENT阻塞,核心原因是TCP TIME_WAIT状态连接耗尽客户端临时端口:

  • 每次请求后调用connection.disconnect()会强制关闭TCP连接,连接断开后会进入TIME_WAIT状态(默认持续60秒,即2倍MSL)
  • 客户端发起新连接时会使用临时端口,当大量连接卡在TIME_WAIT状态,临时端口池被占满,新的SYN包无法分配到可用端口,导致连接卡在SYN_SENT状态等待端口释放
解决方案

1. 复用TCP连接(最优解)

通过HTTP Keep-Alive复用连接,避免每次请求新建TCP连接,从根源上减少TIME_WAIT连接数量。

修改后的Java客户端

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;

public class Client {
    public static void main(String[] args) throws IOException, InterruptedException {
        URL url = new URL("http://localhost:8000");
        while (true) {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            // 开启Keep-Alive,告知服务端保持连接
            connection.setRequestProperty("Connection", "keep-alive");
            // 必须读取响应流,否则连接无法被连接池复用
            int statusCode = connection.getResponseCode();
            System.out.println("Status Code: " + statusCode);
            connection.getInputStream().close();
            // 1ms轮询间隔
            Thread.sleep(1);
            // 不要调用disconnect(),让连接放回连接池复用
        }
    }
}

修改后的Java服务端

服务端需要支持Keep-Alive,循环处理同一连接的多次请求,而非每次请求后关闭连接:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8000);
        while (true) {
            Socket clientSocket = serverSocket.accept();
            // 开启TCP层Keep-Alive,维持连接
            clientSocket.setKeepAlive(true);
            BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            OutputStream outputStream = clientSocket.getOutputStream();
            
            // 循环处理该连接的所有HTTP请求
            while (true) {
                // 读取HTTP请求头,直到空行结束
                String line;
                while ((line = reader.readLine()) != null && !line.isEmpty()) {}
                if (line == null) break; // 连接已关闭
                
                // 返回带Keep-Alive的响应
                outputStream.write("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n".getBytes());
                outputStream.flush();
            }
            clientSocket.close();
        }
    }
}

2. 系统参数调整(短连接场景下的妥协方案)

如果必须使用短连接,可通过调整Linux内核参数缓解端口耗尽问题:

  • 允许TIME_WAIT端口复用:sysctl -w net.ipv4.tcp_tw_reuse=1
  • 缩短TIME_WAIT超时:sysctl -w net.ipv4.tcp_fin_timeout=3
  • 扩大临时端口范围:sysctl -w net.ipv4.ip_local_port_range="1024 65535"

注:以上参数为临时生效,若需永久生效,需写入/etc/sysctl.conf后执行sysctl -p

验证

修改完成后,执行以下命令观测状态:

  • 查看TIME_WAIT连接数量:watch -n 0.1 "ss -on state time-wait '( dport = :8000 )'"
  • 查看SYN_SENT连接数量:watch -n 0.1 "ss -on state syn-sent '( dport = :8000 )'"

正常情况下,TIME_WAIT连接数量会保持稳定,SYN_SENT状态的连接会消失,1ms间隔的轮询可稳定运行。

内容的提问来源于stack exchange,提问作者Elliot Killick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 01:41:05