You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

URCap开发中Java Socket的readUTF()失效问题求助

问题分析与解决方案

核心问题原因

  1. readUTF()不匹配相机返回格式:DataInputStream.readUTF()要求输入是Java特定的UTF-8编码格式(开头带2字节长度前缀),但相机返回的是普通ASCII字符串,没有该前缀,导致方法一直等待长度数据,程序冻结。
  2. readLine()阻塞的可能原因:相机返回的坐标字符串没有换行符(\n或\r\n),readLine()会持续等待换行标记,无法返回结果。
  3. 缺少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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 07:45:14