Java Socket服务器断开异常测试未触发IOException问题排查
问题原因及解决方案
核心问题分析
1. 服务器关闭逻辑未清理已建立连接
你的SocketServer的closeServerSocket()方法仅关闭了用于监听新连接的ServerSocket,但没有关闭已经通过accept()建立的client Socket。TCP连接是双向的,只要一端的Socket未关闭,连接就会保持活跃状态,客户端无法感知服务器已停止服务,自然不会抛出IOException。
2. 服务器构造函数存在变量覆盖bug
构造函数中你定义了局部变量server,覆盖了类成员变量:
// 错误写法:局部变量覆盖成员变量 ServerSocket server = new ServerSocket(tcpPort,0,ipAdress);
这会导致成员变量server始终为null,调用closeServerSocket()时会触发NullPointerException,实际根本没关闭ServerSocket——这可能是测试中服务器看似还在响应的关键原因之一。
3. 客户端读取逻辑不可靠
客户端doStuff()依赖in.available()判断是否有数据可读:
available()仅返回当前输入缓冲区的字节数,无法检测连接关闭(当连接关闭时,read()会返回-1,但available()可能返回0)- 这种写法会导致循环无限空转,或者在未正确检测到连接关闭时意外退出(比如缓冲区残留数据)
4. 测试流程逻辑混乱
测试中关闭旧服务器后,又新建了一个SocketServer实例并设置waitForInstruction=false,但未启动线程——这个新实例和客户端的现有连接完全无关,属于无效操作,反而干扰了测试逻辑。同时,未等待旧服务器线程完全终止就执行客户端操作,存在时序问题。
修复方案
1. 修复服务器关闭逻辑及构造函数
public class SocketServer implements Runnable { // ... 其他成员变量 ... public SocketServer() throws IOException { // 修复变量覆盖问题,使用成员变量 server = new ServerSocket(tcpPort, 0, ipAdress); serverRuns = true; server.setSoTimeout(timeout); } public void closeServerSocket() { try { serverRuns = false; // 关闭已建立的客户端连接 if (client != null && !client.isClosed()) { client.close(); } if (server != null && !server.isClosed()) { server.close(); } } catch (IOException e) { e.printStackTrace(); } } // ... 其他方法 ... }
2. 修复客户端读取逻辑
去掉available()的依赖,直接通过read()检测连接状态:
public void doStuff() throws IOException { String request = "Ok?"; StringBuilder inputStreamString = new StringBuilder(); super.setSoTimeout(timeOut); out = new DataOutputStream(super.getOutputStream()); in = new DataInputStream(super.getInputStream()); out.writeBytes(request); out.flush(); // 确保数据发送到服务器 int c; while ((c = in.read()) != -1) { inputStreamString.append((char) c); if (inputStreamString.toString().equals("Ok")) { break; } } // 如果read()返回-1,说明连接已关闭 if (c == -1) { throw new IOException("Server connection closed unexpectedly"); } System.out.println(inputStreamString); }
3. 修正测试流程
移除无效的服务器实例创建,等待旧线程终止后再执行客户端操作:
@Test public void checkServerisDown() { try { socketClient.connect(); } catch (IOException e) { fail("IO Error during client connect"); } // 关闭服务器,包括已建立的客户端连接 testServer.closeServerSocket(); try { // 等待旧服务器线程终止,超时2秒 monitor.join(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.print("Test (1/1) CHECK SERVER IS DOWN.....\n"); try { socketClient.doStuff(); // 执行到这里说明未抛出预期异常,测试失败 System.out.println("NOT OK!"); fail("Expected IOException when server is down"); } catch (IOException e) { // 捕获到预期异常,测试通过 System.out.println("OK! Caught expected IOException: " + e.getMessage()); } try { socketClient.close(); } catch (IOException e) { fail("IO Error closing client socket"); } }
内容的提问来源于stack exchange,提问作者hcastro
相关产品推荐
相关产品推荐

