如何让Java服务器持续监听客户端连接而不终止

java服务器在处理完一个客户端请求后会退出,是因为当前代码只接受一次连接并读取数据;要实现持续服务,需将接受连接和处理逻辑放入无限循环中,并为每个连接启用独立线程。

你的 Java 服务器当前使用了 try-with-resources 语句包裹 ServerSocket 和首个 Socket,这导致整个资源生命周期仅覆盖单次连接——一旦客户端关闭连接(如 Go 客户端调用 conn.Close()),in.readLi

ne() 返回 null,循环结束,try 块退出,ServerSocket 也被自动关闭,进程随之终止。

✅ 正确做法是:将 serverSocket.accept() 放入外层无限循环,每次接受新连接后,在新线程中处理该连接,从而保证服务器长期运行、并发响应多个客户端。

以下是改进后的 Java 服务器示例(含异常处理与资源管理):

import java.io.*;
import java.net.*;

public class EchoServer {
    public static void main(String[] args) {
        int port = 4444;
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("Echo server started on port " + port);

            // 持续等待并接受新连接
            while (!Thread.currentThread().isInterrupted()) {
                Socket clientSocket = serverSocket.accept();
                System.out.println("New client connected: " + clientSocket.getRemoteSocketAddress());

                // 为每个客户端启动独立线程处理
                new Thread(() -> handleClient(clientSocket)).start();
            }
        } catch (IOException e) {
            System.err.println("Server error: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private static void handleClient(Socket clientSocket) {
        try (
            BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)
        ) {
            String inputLine;
            while ((inputLine = in.readLine()) != null) {
                System.out.println("Received: " + inputLine);
                out.println(inputLine); // 回显
            }
        } catch (IOException e) {
            System.err.println("Client handler error: " + e.getMessage());
        } finally {
            try {
                clientSocket.close();
                System.out.println("Client connection closed.");
            } catch (IOException ignored) {}
        }
    }
}

⚠️ 注意事项:

  • 不要在主线程中直接 readLine() 后阻塞——这会串行化所有请求;务必用多线程(或更优方案如 NIO/Netty)实现并发;
  • ServerSocket 必须在 while 循环外初始化并保持打开状态,否则每次循环都会尝试绑定已占用端口,抛出 BindException;
  • Go 客户端目前未换行(\n),而 readLine() 依赖换行符终止读取——请修改客户端发送带换行的数据:
func main() {
    fmt.Println("start client")
    conn, err := net.Dial("tcp", "localhost:4444")
    if err != nil {
        log.Fatal("Connection error:", err)
    }
    defer conn.Close()

    // ✅ 关键:发送带 \n 的字符串,使 readLine() 正常返回
    _, _ = conn.Write([]byte("hello world\n"))

    // 可选:读取服务器回显(验证通信)
    buf := make([]byte, 128)
    n, _ := conn.Read(buf)
    fmt.Println("Server replied:", string(buf[:n]))

    fmt.Println("done")
}

? 总结:服务器“不终止”的本质是保持 ServerSocket 活跃并持续调用 accept();而“支持多请求”则依赖于连接处理逻辑与主监听循环解耦——推荐始终采用“主线程 accept + 工作线程 handle”模式,这是构建健壮 TCP 服务器的基础范式。