From fef9c80463b0e44ee3fa7a77d0dd02b5cb67c30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E9=9D=96=E7=9A=93?= <16375426+zhou-jinghao1107@user.noreply.gitee.com> Date: Fri, 5 Dec 2025 10:27:34 +0800 Subject: [PATCH] 2 --- README.md | 24 +++++++-- .../java/com/example/echo/EchoClient.java | 2 +- .../java/com/example/echo/EchoServer.java | 50 ++++++++++++------- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 4b3544a..97a3e72 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## 项目简介 -本项目包含一个基础的TCP回声服务器和相应的客户端,服务器将客户端发送的每条消息原样返回给客户端,直到客户端发送"bye"断开连接。 +本项目包含一个支持多客户端并发访问的TCP回声服务器和相应的客户端,服务器将客户端发送的每条消息原样返回给客户端,直到客户端发送"bye"断开连接。 ## 技术栈 @@ -15,10 +15,12 @@ ## 功能特性 -- 单客户端连接处理 +- 多客户端并发连接处理 - 消息回声功能 - 支持断开连接命令("bye") -- 基础错误处理 +- 支持时间查询命令("time") +- 连接/断开日志记录 +- 高效的线程池管理 ## 项目结构 @@ -76,4 +78,18 @@ java -cp target/classes com.example.echo.EchoClient ## 测试 -输入任意消息到客户端,服务器将回传相同的消息加上"Echo: "前缀。输入"bye"可断开连接。 \ No newline at end of file +输入任意消息到客户端,服务器将回传相同的消息加上"Echo: "前缀。输入"bye"可断开连接。输入"time"可获取服务器当前时间。 + +## 设计说明 + +### 多客户端支持 +服务器使用线程池处理多个客户端连接,每个客户端连接由独立线程处理,实现了真正的并发访问。 + +### 线程优化 +使用`Executors.newCachedThreadPool()`替代原来的单线程执行器,可以根据需要创建新线程,但会重用之前构造的线程。对于短期异步任务,这种线程池通常是首选。 + +### 特殊命令支持 +除了基本的回声功能外,还支持"TIME"命令,当客户端发送"TIME"时,服务器会返回当前系统时间。 + +### 日志记录 +详细记录了客户端的连接和断开过程,以及各种操作的日志信息,便于调试和监控。 \ No newline at end of file diff --git a/src/main/java/com/example/echo/EchoClient.java b/src/main/java/com/example/echo/EchoClient.java index 12bf370..17dbb5c 100644 --- a/src/main/java/com/example/echo/EchoClient.java +++ b/src/main/java/com/example/echo/EchoClient.java @@ -18,7 +18,7 @@ public class EchoClient { BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in))) { System.out.println("已连接到Echo服务器: " + SERVER_HOST + ":" + SERVER_PORT); - System.out.println("输入消息发送到服务器 (输入 'bye' 断开连接):"); + System.out.println("输入消息发送到服务器 (输入 'bye' 断开连接,输入 'time' 获取服务器时间):"); String userInput; while ((userInput = stdIn.readLine()) != null) { diff --git a/src/main/java/com/example/echo/EchoServer.java b/src/main/java/com/example/echo/EchoServer.java index f55f684..f6f2462 100644 --- a/src/main/java/com/example/echo/EchoServer.java +++ b/src/main/java/com/example/echo/EchoServer.java @@ -2,13 +2,15 @@ package com.example.echo; import java.io.*; import java.net.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** - * 单客户端Echo服务器 - * 这个服务器一次只处理一个客户端连接 + * 多客户端Echo服务器 + * 这个服务器可以同时处理多个客户端连接 */ public class EchoServer { private static final int PORT = 8888; @@ -17,7 +19,8 @@ public class EchoServer { private ExecutorService executor; public EchoServer() { - executor = Executors.newSingleThreadExecutor(); + // 使用缓存线程池提高效率 + executor = Executors.newCachedThreadPool(); } /** @@ -28,43 +31,56 @@ public class EchoServer { running = true; System.out.println("Echo Server已启动,监听端口: " + PORT); - // 等待客户端连接 - System.out.println("等待客户端连接..."); - Socket clientSocket = serverSocket.accept(); - System.out.println("客户端已连接: " + clientSocket.getRemoteSocketAddress()); - - handleClient(clientSocket); + // 循环接受客户端连接 + while (running) { + System.out.println("等待客户端连接..."); + Socket clientSocket = serverSocket.accept(); + System.out.println("新客户端已连接: " + clientSocket.getRemoteSocketAddress()); + + // 为每个客户端创建一个新任务 + executor.submit(() -> handleClient(clientSocket)); + } } /** * 处理客户端连接 */ private void handleClient(Socket clientSocket) { + String clientAddress = clientSocket.getRemoteSocketAddress().toString(); + System.out.println("开始处理客户端 " + clientAddress + " 的连接"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) { String inputLine; - System.out.println("开始与客户端通信..."); + System.out.println("开始与客户端 " + clientAddress + " 通信..."); while ((inputLine = in.readLine()) != null) { if ("bye".equalsIgnoreCase(inputLine.trim())) { - System.out.println("客户端请求断开连接"); + System.out.println("客户端 " + clientAddress + " 请求断开连接"); break; } - System.out.println("收到消息: " + inputLine); - // 将收到的消息回显给客户端 - out.println("Echo: " + inputLine); + // 特殊命令:TIME - 返回系统时间 + if ("time".equalsIgnoreCase(inputLine.trim())) { + String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + System.out.println("客户端 " + clientAddress + " 请求系统时间: " + currentTime); + out.println("当前系统时间: " + currentTime); + } else { + System.out.println("收到客户端 " + clientAddress + " 的消息: " + inputLine); + // 将收到的消息回显给客户端 + out.println("Echo: " + inputLine); + } } } catch (IOException e) { - System.err.println("处理客户端连接时发生错误: " + e.getMessage()); + System.err.println("处理客户端 " + clientAddress + " 连接时发生错误: " + e.getMessage()); } finally { try { clientSocket.close(); - System.out.println("客户端连接已关闭"); + System.out.println("客户端 " + clientAddress + " 连接已关闭"); } catch (IOException e) { - System.err.println("关闭客户端连接时发生错误: " + e.getMessage()); + System.err.println("关闭客户端 " + clientAddress + " 连接时发生错误: " + e.getMessage()); } } } -- Gitee