From b764e999721f1bcfed5bf73700037f0a29263b0f Mon Sep 17 00:00:00 2001 From: Edward Zhu Date: Thu, 27 Nov 2025 18:15:03 +0800 Subject: [PATCH 1/2] add readme --- .../java/com/example/echo/EchoClient.java | 2 +- .../java/com/example/echo/EchoServer.java | 175 +++++++++++++----- .../echo/com/example/echo/EchoServer.class | Bin 0 -> 8847 bytes 3 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/example/echo/com/example/echo/EchoServer.class diff --git a/src/main/java/com/example/echo/EchoClient.java b/src/main/java/com/example/echo/EchoClient.java index 12bf370..781356b 100644 --- a/src/main/java/com/example/echo/EchoClient.java +++ b/src/main/java/com/example/echo/EchoClient.java @@ -9,7 +9,7 @@ import java.net.*; */ public class EchoClient { private static final String SERVER_HOST = "localhost"; - private static final int SERVER_PORT = 8888; + private static final int SERVER_PORT = 10086; public static void main(String[] args) { try (Socket socket = new Socket(SERVER_HOST, SERVER_PORT); diff --git a/src/main/java/com/example/echo/EchoServer.java b/src/main/java/com/example/echo/EchoServer.java index f55f684..c1d8504 100644 --- a/src/main/java/com/example/echo/EchoServer.java +++ b/src/main/java/com/example/echo/EchoServer.java @@ -1,91 +1,187 @@ package com.example.echo; +import javax.net.ServerSocketFactory; import java.io.*; import java.net.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; /** - * 单客户端Echo服务器 - * 这个服务器一次只处理一个客户端连接 + * 多客户端Echo服务器 + * 强化日志输出,直观体现多客户端同时访问 */ public class EchoServer { - private static final int PORT = 8888; + // 更换为不常用端口,避免冲突 + private static final int PORT = 10086; private ServerSocket serverSocket; private boolean running = false; private ExecutorService executor; + private static final int THREAD_POOL_SIZE = 10; + + // 核心:统计在线客户端(线程安全) + private final AtomicInteger clientCount = new AtomicInteger(0); + // 存储客户端信息(客户端标识 -> 连接时间),线程安全Map + private final Map onlineClients = new ConcurrentHashMap<>(); + // 客户端连接序号(唯一标识) + private final AtomicInteger clientSeq = new AtomicInteger(0); public EchoServer() { - executor = Executors.newSingleThreadExecutor(); + // 线程池命名,便于日志识别 + executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE, r -> { + Thread t = new Thread(r); + t.setName("Client-Handler-" + t.getId()); + return t; + }); } /** * 启动服务器 */ public void start() throws IOException { - serverSocket = new ServerSocket(PORT); + // 端口复用配置,避免重启端口占用 + ServerSocketFactory factory = ServerSocketFactory.getDefault(); + serverSocket = factory.createServerSocket(); + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress(PORT)); + running = true; - System.out.println("Echo Server已启动,监听端口: " + PORT); + System.out.println("===== Echo Server 启动成功 ====="); + System.out.println("监听端口: " + PORT); + System.out.println("线程池大小: " + THREAD_POOL_SIZE); + System.out.println("===============================\n"); + + // 循环接受客户端连接 + while (running) { + System.out.println("\n【服务器状态】等待新客户端连接 | 当前在线客户端数: " + clientCount.get()); + Socket clientSocket = serverSocket.accept(); + + // 生成客户端唯一标识(序号+IP+端口) + int seq = clientSeq.incrementAndGet(); + InetSocketAddress clientAddress = (InetSocketAddress) clientSocket.getRemoteSocketAddress(); + String clientId = String.format("[客户端-%d][%s:%d]", + seq, clientAddress.getHostString(), clientAddress.getPort()); - // 等待客户端连接 - System.out.println("等待客户端连接..."); - Socket clientSocket = serverSocket.accept(); - System.out.println("客户端已连接: " + clientSocket.getRemoteSocketAddress()); + // 在线客户端计数+1 + int currentOnline = clientCount.incrementAndGet(); + // 记录客户端连接信息 + String connectTime = new SimpleDateFormat("HH:mm:ss").format(new Date()); + onlineClients.put(clientId, connectTime); - handleClient(clientSocket); + // 核心日志:新客户端连接,体现并发 + System.out.println("\n========== 新客户端连接 =========="); + System.out.println("客户端标识: " + clientId); + System.out.println("连接时间: " + connectTime); + System.out.println("处理线程: " + Thread.currentThread().getName()); + System.out.println("当前在线总数: " + currentOnline); + System.out.println("在线客户端列表: " + onlineClients.keySet()); + System.out.println("==================================="); + + // 提交到线程池处理(体现并发) + executor.submit(() -> handleClient(clientSocket, clientId)); + } } /** - * 处理客户端连接 + * 处理单个客户端的交互(每个客户端一个线程) */ - private void handleClient(Socket clientSocket) { + private void handleClient(Socket clientSocket, String clientId) { + // 获取当前处理线程信息 + String threadInfo = Thread.currentThread().getName() + "(ID:" + Thread.currentThread().getId() + ")"; + try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) { - String inputLine; - System.out.println("开始与客户端通信..."); + System.out.printf("\n【并发处理】%s 开始交互 | 处理线程: %s\n", clientId, threadInfo); + out.println("欢迎连接Echo服务器!当前在线客户端数: " + clientCount.get()); + out.println("发送 'TIME' 获取系统时间 | 发送 'bye' 断开连接"); + String inputLine; + // 循环读取客户端消息 while ((inputLine = in.readLine()) != null) { - if ("bye".equalsIgnoreCase(inputLine.trim())) { - System.out.println("客户端请求断开连接"); + // 打印并发交互日志(核心:体现多客户端同时发消息) + System.out.printf("\n【并发消息】%s | 线程: %s | 收到消息: %s\n", + clientId, threadInfo, inputLine); + + // 处理TIME命令 + if ("TIME".equalsIgnoreCase(inputLine.trim())) { + String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + out.println("当前时间: " + currentTime); + System.out.printf("【响应】%s | 线程: %s | 返回时间: %s\n", + clientId, threadInfo, currentTime); + } + // 处理断开连接 + else if ("bye".equalsIgnoreCase(inputLine.trim())) { + out.println("再见!当前在线客户端数: " + (clientCount.get() - 1)); + System.out.printf("【主动断开】%s | 线程: %s | 客户端请求断开\n", + clientId, threadInfo); break; } - - System.out.println("收到消息: " + inputLine); - // 将收到的消息回显给客户端 - out.println("Echo: " + inputLine); + // 普通消息回显 + else { + out.println("Echo: " + inputLine); + System.out.printf("【回显响应】%s | 线程: %s | 已回显消息\n", + clientId, threadInfo); + } } } catch (IOException e) { - System.err.println("处理客户端连接时发生错误: " + e.getMessage()); + System.err.printf("\n【连接异常】%s | 线程: %s | 错误: %s\n", + clientId, threadInfo, e.getMessage()); } finally { + // 释放资源 try { - clientSocket.close(); - System.out.println("客户端连接已关闭"); + if (clientSocket != null && !clientSocket.isClosed()) { + clientSocket.close(); + } } catch (IOException e) { - System.err.println("关闭客户端连接时发生错误: " + e.getMessage()); + System.err.printf("【关闭失败】%s | 关闭Socket错误: %s\n", clientId, e.getMessage()); } + + // 在线计数-1 + int currentOnline = clientCount.decrementAndGet(); + // 移除在线客户端列表 + onlineClients.remove(clientId); + + // 核心日志:客户端断开,体现并发状态更新 + System.out.println("\n========== 客户端断开 =========="); + System.out.println("客户端标识: " + clientId); + System.out.println("处理线程: " + threadInfo); + System.out.println("当前在线总数: " + currentOnline); + System.out.println("剩余在线客户端: " + onlineClients.keySet()); + System.out.println("==================================="); } } /** * 停止服务器 */ - public void stop() throws IOException { + public void stop() { running = false; + // 关闭ServerSocket if (serverSocket != null && !serverSocket.isClosed()) { - serverSocket.close(); + try { + serverSocket.close(); + } catch (IOException e) { + System.err.println("关闭ServerSocket失败: " + e.getMessage()); + } } - executor.shutdown(); - try { - if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + // 关闭线程池 + if (executor != null && !executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { executor.shutdownNow(); + Thread.currentThread().interrupt(); } - } catch (InterruptedException e) { - executor.shutdownNow(); } - System.out.println("服务器已停止"); + System.out.println("\n===== Echo Server 已停止 ====="); + System.out.println("最终在线客户端数: " + clientCount.get()); } public static void main(String[] args) { @@ -94,12 +190,7 @@ public class EchoServer { server.start(); } catch (IOException e) { System.err.println("启动服务器时发生错误: " + e.getMessage()); - } finally { - try { - server.stop(); - } catch (IOException e) { - System.err.println("停止服务器时发生错误: " + e.getMessage()); - } + server.stop(); } } } \ No newline at end of file diff --git a/src/main/java/com/example/echo/com/example/echo/EchoServer.class b/src/main/java/com/example/echo/com/example/echo/EchoServer.class new file mode 100644 index 0000000000000000000000000000000000000000..612711668da1ee2f9d055525c3758d4d60e929ad GIT binary patch literal 8847 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 literal 0 HcmV?d00001 -- Gitee From 21a96193449fea577233140e0fe4cbe938b7c081 Mon Sep 17 00:00:00 2001 From: Edward Zhu Date: Thu, 27 Nov 2025 18:15:03 +0800 Subject: [PATCH 2/2] add readme --- .../java/com/example/echo/EchoClient.java | 2 +- .../java/com/example/echo/EchoServer.java | 175 +++++++++++++----- .../echo/com/example/echo/EchoServer.class | Bin 0 -> 8847 bytes 3 files changed, 134 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/example/echo/com/example/echo/EchoServer.class diff --git a/src/main/java/com/example/echo/EchoClient.java b/src/main/java/com/example/echo/EchoClient.java index 12bf370..781356b 100644 --- a/src/main/java/com/example/echo/EchoClient.java +++ b/src/main/java/com/example/echo/EchoClient.java @@ -9,7 +9,7 @@ import java.net.*; */ public class EchoClient { private static final String SERVER_HOST = "localhost"; - private static final int SERVER_PORT = 8888; + private static final int SERVER_PORT = 10086; public static void main(String[] args) { try (Socket socket = new Socket(SERVER_HOST, SERVER_PORT); diff --git a/src/main/java/com/example/echo/EchoServer.java b/src/main/java/com/example/echo/EchoServer.java index f55f684..c1d8504 100644 --- a/src/main/java/com/example/echo/EchoServer.java +++ b/src/main/java/com/example/echo/EchoServer.java @@ -1,91 +1,187 @@ package com.example.echo; +import javax.net.ServerSocketFactory; import java.io.*; import java.net.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; /** - * 单客户端Echo服务器 - * 这个服务器一次只处理一个客户端连接 + * 多客户端Echo服务器 + * 强化日志输出,直观体现多客户端同时访问 */ public class EchoServer { - private static final int PORT = 8888; + // 更换为不常用端口,避免冲突 + private static final int PORT = 10086; private ServerSocket serverSocket; private boolean running = false; private ExecutorService executor; + private static final int THREAD_POOL_SIZE = 10; + + // 核心:统计在线客户端(线程安全) + private final AtomicInteger clientCount = new AtomicInteger(0); + // 存储客户端信息(客户端标识 -> 连接时间),线程安全Map + private final Map onlineClients = new ConcurrentHashMap<>(); + // 客户端连接序号(唯一标识) + private final AtomicInteger clientSeq = new AtomicInteger(0); public EchoServer() { - executor = Executors.newSingleThreadExecutor(); + // 线程池命名,便于日志识别 + executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE, r -> { + Thread t = new Thread(r); + t.setName("Client-Handler-" + t.getId()); + return t; + }); } /** * 启动服务器 */ public void start() throws IOException { - serverSocket = new ServerSocket(PORT); + // 端口复用配置,避免重启端口占用 + ServerSocketFactory factory = ServerSocketFactory.getDefault(); + serverSocket = factory.createServerSocket(); + serverSocket.setReuseAddress(true); + serverSocket.bind(new InetSocketAddress(PORT)); + running = true; - System.out.println("Echo Server已启动,监听端口: " + PORT); + System.out.println("===== Echo Server 启动成功 ====="); + System.out.println("监听端口: " + PORT); + System.out.println("线程池大小: " + THREAD_POOL_SIZE); + System.out.println("===============================\n"); + + // 循环接受客户端连接 + while (running) { + System.out.println("\n【服务器状态】等待新客户端连接 | 当前在线客户端数: " + clientCount.get()); + Socket clientSocket = serverSocket.accept(); + + // 生成客户端唯一标识(序号+IP+端口) + int seq = clientSeq.incrementAndGet(); + InetSocketAddress clientAddress = (InetSocketAddress) clientSocket.getRemoteSocketAddress(); + String clientId = String.format("[客户端-%d][%s:%d]", + seq, clientAddress.getHostString(), clientAddress.getPort()); - // 等待客户端连接 - System.out.println("等待客户端连接..."); - Socket clientSocket = serverSocket.accept(); - System.out.println("客户端已连接: " + clientSocket.getRemoteSocketAddress()); + // 在线客户端计数+1 + int currentOnline = clientCount.incrementAndGet(); + // 记录客户端连接信息 + String connectTime = new SimpleDateFormat("HH:mm:ss").format(new Date()); + onlineClients.put(clientId, connectTime); - handleClient(clientSocket); + // 核心日志:新客户端连接,体现并发 + System.out.println("\n========== 新客户端连接 =========="); + System.out.println("客户端标识: " + clientId); + System.out.println("连接时间: " + connectTime); + System.out.println("处理线程: " + Thread.currentThread().getName()); + System.out.println("当前在线总数: " + currentOnline); + System.out.println("在线客户端列表: " + onlineClients.keySet()); + System.out.println("==================================="); + + // 提交到线程池处理(体现并发) + executor.submit(() -> handleClient(clientSocket, clientId)); + } } /** - * 处理客户端连接 + * 处理单个客户端的交互(每个客户端一个线程) */ - private void handleClient(Socket clientSocket) { + private void handleClient(Socket clientSocket, String clientId) { + // 获取当前处理线程信息 + String threadInfo = Thread.currentThread().getName() + "(ID:" + Thread.currentThread().getId() + ")"; + try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) { - String inputLine; - System.out.println("开始与客户端通信..."); + System.out.printf("\n【并发处理】%s 开始交互 | 处理线程: %s\n", clientId, threadInfo); + out.println("欢迎连接Echo服务器!当前在线客户端数: " + clientCount.get()); + out.println("发送 'TIME' 获取系统时间 | 发送 'bye' 断开连接"); + String inputLine; + // 循环读取客户端消息 while ((inputLine = in.readLine()) != null) { - if ("bye".equalsIgnoreCase(inputLine.trim())) { - System.out.println("客户端请求断开连接"); + // 打印并发交互日志(核心:体现多客户端同时发消息) + System.out.printf("\n【并发消息】%s | 线程: %s | 收到消息: %s\n", + clientId, threadInfo, inputLine); + + // 处理TIME命令 + if ("TIME".equalsIgnoreCase(inputLine.trim())) { + String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + out.println("当前时间: " + currentTime); + System.out.printf("【响应】%s | 线程: %s | 返回时间: %s\n", + clientId, threadInfo, currentTime); + } + // 处理断开连接 + else if ("bye".equalsIgnoreCase(inputLine.trim())) { + out.println("再见!当前在线客户端数: " + (clientCount.get() - 1)); + System.out.printf("【主动断开】%s | 线程: %s | 客户端请求断开\n", + clientId, threadInfo); break; } - - System.out.println("收到消息: " + inputLine); - // 将收到的消息回显给客户端 - out.println("Echo: " + inputLine); + // 普通消息回显 + else { + out.println("Echo: " + inputLine); + System.out.printf("【回显响应】%s | 线程: %s | 已回显消息\n", + clientId, threadInfo); + } } } catch (IOException e) { - System.err.println("处理客户端连接时发生错误: " + e.getMessage()); + System.err.printf("\n【连接异常】%s | 线程: %s | 错误: %s\n", + clientId, threadInfo, e.getMessage()); } finally { + // 释放资源 try { - clientSocket.close(); - System.out.println("客户端连接已关闭"); + if (clientSocket != null && !clientSocket.isClosed()) { + clientSocket.close(); + } } catch (IOException e) { - System.err.println("关闭客户端连接时发生错误: " + e.getMessage()); + System.err.printf("【关闭失败】%s | 关闭Socket错误: %s\n", clientId, e.getMessage()); } + + // 在线计数-1 + int currentOnline = clientCount.decrementAndGet(); + // 移除在线客户端列表 + onlineClients.remove(clientId); + + // 核心日志:客户端断开,体现并发状态更新 + System.out.println("\n========== 客户端断开 =========="); + System.out.println("客户端标识: " + clientId); + System.out.println("处理线程: " + threadInfo); + System.out.println("当前在线总数: " + currentOnline); + System.out.println("剩余在线客户端: " + onlineClients.keySet()); + System.out.println("==================================="); } } /** * 停止服务器 */ - public void stop() throws IOException { + public void stop() { running = false; + // 关闭ServerSocket if (serverSocket != null && !serverSocket.isClosed()) { - serverSocket.close(); + try { + serverSocket.close(); + } catch (IOException e) { + System.err.println("关闭ServerSocket失败: " + e.getMessage()); + } } - executor.shutdown(); - try { - if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + // 关闭线程池 + if (executor != null && !executor.isShutdown()) { + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { executor.shutdownNow(); + Thread.currentThread().interrupt(); } - } catch (InterruptedException e) { - executor.shutdownNow(); } - System.out.println("服务器已停止"); + System.out.println("\n===== Echo Server 已停止 ====="); + System.out.println("最终在线客户端数: " + clientCount.get()); } public static void main(String[] args) { @@ -94,12 +190,7 @@ public class EchoServer { server.start(); } catch (IOException e) { System.err.println("启动服务器时发生错误: " + e.getMessage()); - } finally { - try { - server.stop(); - } catch (IOException e) { - System.err.println("停止服务器时发生错误: " + e.getMessage()); - } + server.stop(); } } } \ No newline at end of file diff --git a/src/main/java/com/example/echo/com/example/echo/EchoServer.class b/src/main/java/com/example/echo/com/example/echo/EchoServer.class new file mode 100644 index 0000000000000000000000000000000000000000..612711668da1ee2f9d055525c3758d4d60e929ad GIT binary patch literal 8847 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 literal 0 HcmV?d00001 -- Gitee