使用BufferedReader读取InputStream时如何跳出while读取死循环
问题原因
BufferedReader.readLine() 返回null的唯一前提是绑定的输入流已经到达末尾,没有可读取内容且流已关闭。在Socket场景下循环无法退出,本质是数据发送端发完JSON内容后,没有关闭输出流或者给出传输结束信号,readLine() 读完当前已收到的JSON数据后,会一直阻塞等待对端发送新数据,永远拿不到null返回值,自然无法跳出循环。
你当前的代码逻辑是默认读取到流彻底关闭才停止,和「单次读取一段JSON就完成本次接收」的需求不匹配。
解决方案
根据你的场景选以下任意一种方案即可:
- 约定传输结束标记
收发双方提前约定一个不会和JSON正文冲突的结束标识,比如单独一行传EOF,发送端发完完整JSON后额外发一行这个标识,接收端读到标识就主动跳出循环。
参考代码:String line; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { if ("EOF".equals(line)) { break; } sb.append(line); } - 前置传输数据长度
发送端在发JSON正文前,先把JSON字符串的总长度发过来,接收端按照长度读取对应字节数后就停止读取,这是网络传输场景的通用标准方案,不会出现标识和正文冲突的问题。 - 发送端主动关闭输出流
如果是单次传输场景,发送端写完JSON内容后,调用shutdownOutput()关闭自身的输出流(不要直接关闭整个Socket,避免数据未发送完成就断连),接收端读完所有数据后readLine()就会返回null,循环正常退出。 - 设置Socket读取超时
给Socket设置超时参数:socket.setSoTimeout(3000),单位是毫秒,当连续3秒没有读到新数据时会抛出SocketTimeoutException,捕获异常后跳出循环即可。这种方案适合无法修改发送端逻辑的场景,注意超时时间要结合实际网络情况调整,避免正常传输过程中误触发超时。
注意:如果传输的是带换行的格式化JSON,
readLine()会自动丢弃每行末尾的换行符,拼接后的字符串会丢失原有换行,如果JSON组件对格式校验严格,append的时候需要手动补上\n。
内容的提问来源于stack exchange,提问作者Yondela Sasayi
相关产品推荐
相关产品推荐

