在socket上发送int作为byte []然后重新转换为int不起作用

时间:2016-05-06 22:29:35

标签: java sockets casting nio

我正在尝试在NIO SocketChannel和阻塞IO套接字之间序列化Object。由于我不能在NIO上使用Serializable / writeObject,我想编写代码将对象序列化为ByteArrayOutputStream然后发送数组长度后跟数组。

发件人功能

public void writeObject(Object obj) throws IOException{
    ByteArrayOutputStream serializedObj = new ByteArrayOutputStream();
    ObjectOutputStream writer = new ObjectOutputStream(serializedObj);
    writer.writeUnshared(obj);
    ByteBuffer size =        ByteBuffer.allocate(4).putInt(serializedObj.toByteArray().length);

    this.getSocket().write(size);
    this.getSocket().write(ByteBuffer.wrap(serializedObj.toByteArray()));
}

和接收者是:

public Object readObject(){
    try {
        //Leggi dimensione totale pacchetto
        byte[] dimension = new byte[4];

        int byteRead = 0;

        while(byteRead < 4) {
            byteRead += this.getInputStream().read(dimension, byteRead, 4 - byteRead);
        }

        int size = ByteBuffer.wrap(dimension).getInt(); /* (*) */
        System.out.println(size);

        byte[] object = new byte[size];

        while(size > 0){
            size -= this.getInputStream().read(object);
        }

        InputStream in = new ByteArrayInputStream(object, 0, object.length);
        ObjectInputStream ois = new ObjectInputStream(in);
        Object res = ois.readUnshared();
        ois.close();
        return res;
    } catch (IOException | ClassNotFoundException e) {
        return null;
    }
}

问题是当serializedObj.toByteArray()时,size(*)总是等于-1393754107。我的测试中的长度是316。 我不明白为什么投射不能正常工作。

2 个答案:

答案 0 :(得分:1)

this.getSocket().write(size);
this.getSocket().write(ByteBuffer.wrap(serializedObj.toByteArray()));

如果getSocket()的结果在非阻止模式下为SocketChannel,则问题出在此处。您没有检查write()的结果。在非阻塞模式下,它可以写入少于ByteBuffer中剩余的字节数;实际上它可以写零个字节。

所以你没有写出你认为自己正在写的所有数据,所以另一端超出并读取下一个长度字作为正在写入的数据的一部分,并将下一个数据的一部分读取为下一个长度的单词,得到错误的答案。我很惊讶它早些时候没有barf。事实上它可能会这样做,但是你忽视IOExceptions的令人遗憾的做法掩盖了它。不要这样做。 记录他们。

所以你需要循环,直到所有请求的数据都被写入,如果任何write()返回零,你需要在OP_WRITE上选择直到它被触发,这会给你的代码带来相当大的复杂性,因为你必须返回选择循环,同时记住有一个未完成的ByteBuffer,其中还有待写入的数据。当你获得OP_WRITE并完成写入时,你必须注销对OP_WRITE的兴趣,因为在write()返回零之后它只是感兴趣。

注意您的代码中没有强制转换。

答案 1 :(得分:0)

问题是write()总是返回0。发生这种情况是因为在write()之前没有翻转缓冲区。