题目
实现一个支持多客户端的TCP时间服务器
信息
- 类型:问答
- 难度:⭐⭐
考点
Socket编程,多线程处理,资源管理,异常处理
快速回答
实现要点:
- 使用
ServerSocket在指定端口监听 - 循环接受客户端连接,为每个连接创建独立线程
- 使用
BufferedWriter发送当前时间后立即关闭连接 - 使用线程池管理线程资源
- 关键异常处理:
IOException和中断异常
原理说明
TCP时间服务器基于客户端-服务器模型:
1. 服务器通过ServerSocket持续监听端口
2. 客户端通过Socket发起连接请求
3. 每个连接独立线程处理,避免阻塞主线程
4. 遵循TCP协议保证可靠数据传输
代码示例
import java.io.*;
import java.net.*;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TimeServer {
private static final int PORT = 8080;
private static final int MAX_THREADS = 10;
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(MAX_THREADS);
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
System.out.println("时间服务器启动,端口:" + PORT);
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = serverSocket.accept();
pool.execute(() -> handleClient(clientSocket));
}
} catch (IOException e) {
System.err.println("服务器异常:" + e.getMessage());
} finally {
pool.shutdown();
}
}
private static void handleClient(Socket socket) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()))) {
String response = "当前时间:" + LocalDateTime.now() + "\n";
writer.write(response);
writer.flush();
} catch (IOException e) {
System.err.println("客户端处理失败:" + e.getMessage());
} finally {
try {
socket.close(); // 关键:显式关闭连接
} catch (IOException ex) {
System.err.println("关闭连接异常:" + ex.getMessage());
}
}
}
}最佳实践
- 线程池管理:使用
Executors.newFixedThreadPool避免线程频繁创建销毁 - 资源释放:在finally块中确保关闭Socket(try-with-resources更佳)
- 响应协议:发送数据后立即关闭连接符合时间服务场景
- 优雅退出:通过
Thread.currentThread().isInterrupted()检测中断信号
常见错误
- 资源泄漏:未关闭Socket或Writer导致文件描述符耗尽
- 线程爆炸:直接
new Thread()处理连接,高并发时崩溃 - 阻塞主线程:在
handleClient中执行耗时操作 - 编码问题:未指定字符集导致乱码(示例中依赖平台默认编码)
扩展知识
- NIO模型:使用
java.nio.channels.ServerSocketChannel实现非阻塞IO,支持更高并发 - 协议设计:生产环境应定义消息边界(如长度前缀或分隔符)
- 超时控制:通过
socket.setSoTimeout()防止客户端无响应 - 安全加固:对客户端IP做白名单限制,防止DDoS攻击