Java TCP传输场景下如何让无限while循环遇异常仍持续执行
问题根因
- 循环直接终止的核心原因是未捕获的运行时异常直接击穿了循环逻辑:
- 你的
dataTransmission方法里,Socket连接失败时仅捕获了IOException,但连接失败后s1、is、pwr等对象均为null,后续代码直接调用pwr.println()、is.close()等方法时会抛出NullPointerException,这类运行时异常没有被当前方法的try块捕获。 loop方法的catch块仅捕获InterruptedException,其他所有异常(包括上面的空指针、其他运行时异常)都会直接终止外层的while(true)循环。
- 你的
- 附加逻辑bug:
dataTransmission方法参数定义顺序和调用时传参顺序完全相反,会导致实际传入的IP和GSID取值错乱- 代码硬编码了服务器地址为
localhost,没有使用调用时传入的serverIP参数 - sleep逻辑放在了传输执行完成后才触发,传输失败时不会触发等待,会导致无间隔疯狂重试打满CPU。
修正方案
第一步:调整循环的异常捕获逻辑
外层循环兜底捕获所有可能抛出的异常,同时把sleep逻辑放到finally块里,保证不管传输成功还是失败,都会等待10秒再重试,符合固定间隔要求。
修正后的loop方法:
public void loop(String serverIP, String GSID) { while (true) { try { // 注意参数顺序要和方法定义匹配 dataTransmission(GSID, serverIP); } catch (Exception e) { // 兜底捕获所有传输过程中抛出的异常,避免循环击穿 System.out.println("本次传输失败,10秒后重试:" + e.getMessage()); } finally { // 不管成功还是失败,都固定等待10秒 try { TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) { System.out.println("循环被中断:" + e.getMessage()); // 如需中断退出可加break,保持持续运行则无需额外处理 } } } }
第二步:修正dataTransmission方法的空指针和资源问题
- 所有流、Socket对象在操作前先判空,连接失败直接return,不执行后续写数据、关资源的逻辑
- 修正参数顺序,用传入的serverIP替代硬编码的localhost
- 资源关闭统一在finally块处理,每个对象先判空,避免空指针
- 所有IO操作的异常都在方法内部兜住,或者直接抛出给外层循环统一处理
修正后的dataTransmission方法:
public void dataTransmission(String GSID, String serverIP) { System.out.println("GS ID=" + GSID); System.out.println("server IP=" + serverIP); Socket s1 = null; BufferedReader br = null; BufferedReader is = null; PrintWriter pwr = null; try { // 用传入的serverIP替代硬编码的localhost s1 = new Socket(serverIP, 4445); br = new BufferedReader(new InputStreamReader(System.in)); is = new BufferedReader(new InputStreamReader(s1.getInputStream())); pwr = new PrintWriter(s1.getOutputStream()); // 只有连接成功才执行后续传输逻辑 // 发送GSID pwr.println(GSID); pwr.flush(); // 获取本机IP GetGasStationIP gsip = new GetGasStationIP(); String GSIP = gsip.getSourceIP(); // 发送本机IP pwr.println(GSIP); pwr.flush(); // 发送当前时间 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String nowTime = dtf.format(LocalDateTime.now()); pwr.println(nowTime); pwr.flush(); } catch (IOException | UnknownHostException e) { // 所有连接、传输、IP获取的异常都在这里捕获,直接打印日志即可 System.out.println("传输过程异常:" + e.getMessage()); return; // 异常后直接返回,不执行后续关资源逻辑 } finally { // 资源关闭统一在finally里处理,每个对象先判空 try { if (br != null) br.close(); if (is != null) is.close(); if (pwr != null) pwr.close(); if (s1 != null) s1.close(); } catch (IOException e) { System.out.println("资源关闭异常:" + e.getMessage()); } } System.out.println("本次连接处理完成"); System.out.println(""); }
额外优化建议
- 可以给Socket加连接超时,避免连接卡很久才触发异常:
s1 = new Socket(); s1.connect(new InetSocketAddress(serverIP, 4445), 3000);即3秒连不上就直接判定连接失败,进入重试。 - 异常日志打印的时候可以加时间戳,方便排查问题。
- 如果是生产环境使用,建议加最大重试次数、指数退避间隔,避免服务器宕机时产生大量无效请求。
内容的提问来源于stack exchange,提问作者rouiiii
相关产品推荐
相关产品推荐

