首页 > 解决方案 > 网络 ObjectOutputStream 中的奇数 ArrayIndexOutOfBoundsException

问题描述

我有一个不断向服务器发送消息的客户端。最终我得到了一个我无法理解的ArrayIndexOutOfBoundsException内部:writeObject

Exception in thread "Core" java.lang.ArrayIndexOutOfBoundsException: Index 256 out of bounds for length 256
        at java.base/java.io.ObjectOutputStream$BlockDataOutputStream.writeBytes(ObjectOutputStream.java:1996)
        at java.base/java.io.ObjectOutputStream$BlockDataOutputStream.writeUTF(ObjectOutputStream.java:2174)
        at java.base/java.io.ObjectOutputStream.writeString(ObjectOutputStream.java:1307)
        at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1173)
        at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349)
        at ws.hikari.md5.ui.network.Client.sendStatusMessage(Client.java:64)
        at ws.hikari.md5.Core.run(Core.java:96)
        at java.base/java.lang.Thread.run(Thread.java:834)

在这里ws.hikari.md5.ui.network.Client.sendStatusMessage(),它被Core调用以将消息发送到服务器。

public class Client implements Runnable {
// ...

    protected ObjectOutputStream oos = null;

    public boolean connect(){
        
        try{
            socket = new Socket(
                // host IP,
                // host port
            );
            oos = new ObjectOutputStream(socket.getOutputStream());
        
        }catch(IOException ex){
            logger.log(Level.FINER,"Client connect failed",ex);
            return false;
        }
        
        return true;
    }

    protected boolean sendStatusMessage(Message msg){
        if(null==socket || null==oos){
            connect();
            return false;
        }
        
    
        GsonBuilder builder = new GsonBuilder();
        builder.setPrettyPrinting().serializeNulls();
        Gson gson = builder.create();
        
        String serializedMsg = gson.toJson(msg);
        
        try{
            oos.writeObject(serializedMsg); // line 64
        }catch(SocketException ex){
            // just silence it, it's ok if Remote GUI server is offline
            connect();
            return false;
        }catch(IOException ex){
            logger.throwing("Client", "sendStatusMessage", ex);

            connect();
            return false;
        }
        
        return true;
    }
    
// ...
}

标签: javasockets

解决方案


您同时ObjectOutputStream从多个线程写入相同的内容。这是不支持的。

来源: 来源的一小部分java.io.ObjectOutputStream

                int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
                int stop = pos + n;
                while (pos < stop) {
                    buf[pos++] = (byte) cbuf[cpos++];
                }

其中pos是与 OOS 关联的 BlockDataOutputStream 实例的字段;各种写入方法会影响它,如果在这两行之间对其进行修改,cbuf(硬编码为 256 大, vs buf,硬编码为 1024,因此发生的错误是因为cpos是 256,因此cbuf[cpos++]是导致 AIOOBEx 的行,not buf[pos++],这是因为stop太大,这是因为在第 1 行 ( ) 和第 2 行pos 之间进行了修改。int n =...

您无法更改 ObjectOutputStream 的来源,无论如何,这种“崩溃”不是它的错,它的规范,像大多数 OutputStreams 一样,很清楚尝试从多个线程写入它们会导致完全混乱。


推荐阅读