URCap开发中Java Socket的readUTF()失效问题求助
问题分析与解决方案
核心问题原因
readUTF()不匹配相机返回格式:DataInputStream.readUTF()要求输入是Java特定的UTF-8编码格式(开头带2字节长度前缀),但相机返回的是普通ASCII字符串,没有该前缀,导致方法一直等待长度数据,程序冻结。readLine()阻塞的可能原因:相机返回的坐标字符串没有换行符(\n或\r\n),readLine()会持续等待换行标记,无法返回结果。- 缺少Socket超时设置:未设置Socket读取超时,一旦相机返回异常或未发送数据,程序会无限阻塞。
解决方案
方案1:按字节读取(适配无换行的返回内容)
如果相机返回的坐标字符串无固定长度但会主动关闭输出流,可直接读取字节流直到结束,同时设置超时避免无限阻塞:
private static void socketCommunication(ScriptWriter writer, String ip, int port) { try{ Socket s = new Socket(ip, port); // 设置5秒读取超时,防止程序无限冻结 s.setSoTimeout(5000); OutputStream out = s.getOutputStream(); // 按ASCII编码发送指令,和相机预期格式匹配 out.write("Run.LocateAll,3".getBytes(StandardCharsets.US_ASCII)); out.flush(); // 确保指令完全发送 // 读取相机返回的字节流 InputStream in = s.getInputStream(); byte[] buffer = new byte[1024]; int bytesRead = in.read(buffer); if (bytesRead > 0) { String result = new String(buffer, 0, bytesRead, StandardCharsets.US_ASCII); System.out.println("相机返回坐标:" + result); } // 按顺序关闭资源 in.close(); out.close(); s.close(); } catch(SocketTimeoutException e) { System.out.println("读取超时:相机未在指定时间内返回数据"); } catch(Exception e) { System.out.println("通信异常:" + e.getMessage()); } }
方案2:用BufferedReader读取(适配带换行的返回内容)
如果相机支持在返回坐标后添加换行符,可使用BufferedReader简化读取:
private static void socketCommunication(ScriptWriter writer, String ip, int port) { try{ Socket s = new Socket(ip, port); s.setSoTimeout(5000); OutputStream out = s.getOutputStream(); out.write("Run.LocateAll,3".getBytes(StandardCharsets.US_ASCII)); out.flush(); BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream(), StandardCharsets.US_ASCII)); String result = reader.readLine(); if (result != null) { System.out.println("相机返回坐标:" + result); } reader.close(); out.close(); s.close(); } catch(SocketTimeoutException e) { System.out.println("读取超时"); } catch(Exception e) { System.out.println("异常:" + e.getMessage()); } }
额外注意事项
- 编码一致性:发送和接收统一使用
US_ASCII编码,和相机的通信格式匹配,避免乱码。 - 资源安全关闭:推荐使用try-with-resources语法自动管理资源,避免泄漏:
try (Socket s = new Socket(ip, port); OutputStream out = s.getOutputStream(); InputStream in = s.getInputStream()) { s.setSoTimeout(5000); out.write("Run.LocateAll,3".getBytes(StandardCharsets.US_ASCII)); out.flush(); byte[] buffer = new byte[1024]; int bytesRead = in.read(buffer); if (bytesRead > 0) { String result = new String(buffer, 0, bytesRead, StandardCharsets.US_ASCII); System.out.println(result); } } catch(SocketTimeoutException e) { System.out.println("读取超时"); } catch(Exception e) { System.out.println(e.getMessage()); } - 关于
writeUTF()的问题:DataOutputStream.writeUTF()会在字符串前添加2字节长度前缀,这就是相机收到%Run.LocateAll的原因(前缀字节被解析成%),因此必须用writeBytes()或直接用OutputStream.write()发送原始字节流。
内容的提问来源于stack exchange,提问作者Searcher
相关产品推荐
相关产品推荐

