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
相关产品推荐
相关产品推荐

