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

复用Socket向ESP32服务器发送多HTTP请求时程序停滞问题

问题原因分析
  1. 协议版本不匹配:客户端发送HTTP/2请求,但ESP32服务器返回HTTP/1.1响应——多数ESP32内置HTTP服务器仅支持HTTP/1.1,协议不兼容会导致后续处理异常。
  2. 响应读取逻辑错误:你用while ((line = reader.readLine()) != null)循环读取响应,readLine()会一直阻塞直到读到换行符或输入流关闭。服务器返回的响应包含Content-Length: 2的响应体(2个字节、无换行),读完响应头的空行后,readLine()会持续等待换行,直接导致程序停滞。
  3. 服务器不支持长连接:服务器返回Connection: close,说明它会在本次请求后主动关闭连接,即使客户端指定Connection: keep-alive也无法复用该Socket,后续请求自然无法正常执行。
修复方案

1. 修正HTTP协议版本

将请求中的HTTP/2改为HTTP/1.1,同时严格遵循HTTP协议规范用\r\n作为头信息换行符:

output.write(
    String.format(
        "GET /%s HTTP/1.1\r\n"
      + "Host: %s\r\n"
      + "Connection: keep-alive\r\n"
      + "\r\n",
        x, hostname
    )
);

2. 正确读取HTTP响应

不能依赖readLine()一直读到流结束,需要按HTTP响应结构分步读取:先读取响应头并解析Content-Length,再读取对应长度的响应体,读完即停止循环避免阻塞:

System.out.println("h2");

String line;
int contentLength = 0;

// 读取响应头,空行代表头信息结束
while ((line = reader.readLine()) != null) {
    System.out.println(line);
    // 解析响应体长度
    if (line.startsWith("Content-Length:")) {
        contentLength = Integer.parseInt(line.split(":")[1].trim());
    }
    if (line.isEmpty()) {
        break;
    }
}

// 读取指定长度的响应体
if (contentLength > 0) {
    char[] buffer = new char[contentLength];
    int read = reader.read(buffer, 0, contentLength);
    System.out.println(new String(buffer, 0, read));
}

System.out.println("h3");

3. 适配服务器关闭连接的情况

如果服务器始终返回Connection: close,说明它不支持长连接,此时无法复用Socket,需在每次请求前重新创建Socket和流:

for(int i=1; i<50; i++)
{
    String x = i%2==0 ? "on" : "off";
    
    System.out.println("h1");
    
    // 每次请求重新初始化Socket与流
    socket = new Socket(hostname, port);
    PrintWriter output = new PrintWriter(socket.getOutputStream());
    BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    
    output.write(
        String.format(
            "GET /%s HTTP/1.1\r\n"
          + "Host: %s\r\n"
          + "\r\n",
            x, hostname
        )
    );
    output.flush();
    
    System.out.println("h2");
    
    // 用修正后的逻辑读取响应
    String line;
    int contentLength = 0;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
        if (line.startsWith("Content-Length:")) {
            contentLength = Integer.parseInt(line.split(":")[1].trim());
        }
        if (line.isEmpty()) {
            break;
        }
    }
    if (contentLength > 0) {
        char[] buffer = new char[contentLength];
        int read = reader.read(buffer, 0, contentLength);
        System.out.println(new String(buffer, 0, read));
    }
    
    System.out.println("h3");
    
    // 关闭当前请求的资源
    reader.close();
    output.close();
    socket.close();
    
    Thread.sleep(200);
}

4. 优化ESP32服务器支持长连接(可选)

如果想实现Socket复用,需修改ESP32服务器代码,确保它支持Connection: keep-alive并在响应中返回该字段,而非Connection: close。例如在Arduino环境下,确保server.handleClient()持续处理客户端连接,不主动关闭Socket。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 17:15:53