Java Spring boot Socket 字节数组接收中文字符串 截断bug

  • Post author:
  • Post category:java


  • 场景描述:

    在spring boot中使用sokect 接受来自PHP服务器的执行结果。发送请求后得到的内容中含有乱码,确认了所有编码格式均为UTF-8,并且php端调用的接口所使用的方法执行后返回的是正常的结果。因此怀疑是否是因为Spring boot Socket问题导致,再搜索文章并且调试之后,发现并非此原因。 网上推荐使用BufferReader读取 但是内置方法不包含按byte[]读取,因此放弃。 还有一种解释是说UTF-8中文为3个字节,符号数字为单字节,如果以1024长度的字节数组截取有可能第1023为中文的半个字符,而下一个字符到了下一组中。而此时因为已经使用toString获取了字符串,就导致了最后一个字符为乱码。

  • 解决方案:

    使用ByteBuffer先预存所有的byte[],在读取完所有数据之后,再进行String的转换。

  • 代码:

        String reqStr="请求内容";
        ByteBuffer buf = ByteBuffer.allocate(4 + reqStr.getBytes().length);
        buf.putInt(reqStr.getBytes().length);
        buf.put(reqStr.getBytes());
        //socket连接设置   1.7语法糖
        Socket socket=new Socket(jobTagSocketHost,config.getApiSocketPort());)
        {
        //调用内部socket接口
        socket.getOutputStream().write(buf.array());//发送请求字符串
        //读取数据长度
        byte[] size = new byte[4];
        socket.getInputStream().read(size);
        int size_t = Bytes.toInt(size, 0, 4);
        //读取数据,每次读取1024字节,防止数据丢失,或读不全
        byte[] data = new byte[1024];
        //如果不使用bytebuffer 会导致循环时转换的最后一个字节有可能是中文的半个字节
        ByteBuffer bb= ByteBuffer.allocate(size_t);
        while (size_t > 0) {
            int dataSize = socket.getInputStream().read(data);
            bb.put(Arrays.copyOfRange(data, 0, dataSize));
            size_t -= dataSize;
        }
        //最终-查询结果字符串
        String finalStr = new String(bb.array());
  • 问题:

    有可能会有大量数据情况 会导致OOM发生,预申请的空间可能过大,需要在申请前进行判断,如果超过某个大小则抛出异常。比如 size为2048000000 ,2G 则必然会在小jvm设置下发生 java heap out of memory 问题。



版权声明:本文为qq_39259062原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。