Java C/S开发中BufferedReader.readLine()返回null问题咨询
问题原因
BufferedReader.readLine()返回null没有其他可能性,唯一触发条件是当前读取的输入流已经到达流末尾,也就是TCP连接的对端已经关闭了输出流、或者直接断开了连接,后续不会再有任何数据传入。
你的代码出现这个问题,基本是以下几个原因导致的:
- 客户端和服务端的通信协议约定没有对齐:你客户端的逻辑是等服务端返回
exit字符串作为列表传输结束的标记,但如果服务端发完房间人数、发完列表内容之后,没有写入exit行就直接关闭了流或者socket,客户端读完所有有效数据后再调用readLine()就会直接拿到null。此时你的while循环判断!"exit".equals(msgFromServ = br.readLine())会因为null不等于"exit"直接进入循环体,后续的字符串比较、插入列表操作都会触发空指针异常。 - 流重复创建的隐患:你每次触发这个刷新方法时,都会基于现有socket重新创建一次
BufferedReader和PrintWriter。如果这个socket是长连接、之前已经创建过未关闭的IO流,重复包装输入流很容易导致流指针错乱、读到截断数据,甚至触发服务端的连接重置逻辑,主动断开连接。 - 异常捕获逻辑吞掉了根因:你现在的catch块只打印了一句固定的方法名日志,没有输出任何异常信息。很多时候连接断开是IO异常(比如连接超时、连接重置)导致的,异常被吞掉之后你只能看到后续
readLine()返回null的表象,看不到连接断开的真实原因。
修复方案
- 首先修正循环的判断逻辑,永远不要假设对端一定会按照约定发送结束标记,必须先判断
readLine()返回值是否为null,再做内容匹配。 - 长连接场景下不要重复创建IO流,在socket连接建立完成时初始化一次
BufferedReader和PrintWriter,全局复用即可,避免流状态混乱。 - 补全异常日志,打印完整的异常信息方便定位问题,同时在读取到null时给出明确的连接断开提示。
- 排查服务端对应逻辑,确认返回完所有房间列表数据后,一定会写入
exit行作为结束标记,并且在所有数据flush完成后再关闭连接;如果服务端处理请求时抛出异常,也要走统一的错误返回逻辑,不要直接断开连接。
修正后的核心代码参考:
try { // 注意:如果是长连接,br和pw不要在这个方法里新建,提到连接初始化的位置创建复用 BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); PrintWriter pw = new PrintWriter(sock.getOutputStream(), true); pw.println("refreshRoomOnClient"); countClientInRoomFromServer = br.readLine(); // 读取到null直接返回,避免操作空值 if (countClientInRoomFromServer == null) { txtLogs.append("连接已断开,无法获取房间人数\n"); return; } lblCountClientInRoom.setText("Clients in the room: " + countClientInRoomFromServer); pw.println(txtNameRoom.getText()); listModelRoom.removeAllElements(); int size_listModelRoom = listModelRoom.size(); String msgFromServ; // 先判空,再判断是否是结束标记 while ((msgFromServ = br.readLine()) != null && !"exit".equals(msgFromServ)) { System.out.println(msgFromServ); if ("Cant find File".equals(msgFromServ)) { txtLogs.append("Can't find files" + "\n"); break; } else if ("error".equals(msgFromServ)) { txtLogs.append("Error reading" + "\n"); break; } listModelRoom.insertElementAt(msgFromServ, size_listModelRoom); } // 循环因为读到null退出,说明连接异常断开 if (msgFromServ == null) { txtLogs.append("服务端连接中断,房间列表加载不完整\n"); } } catch (IOException ex) { // 打印具体异常信息,不要只打固定文案 txtLogs.append("刷新房间列表异常: " + ex.getMessage() + "\n"); ex.printStackTrace(); }
内容的提问来源于stack exchange,提问作者David Shamsani
相关产品推荐
相关产品推荐

