发送int作为字节[],然后重新编程int int不工作

问题描述:

我想在NIO SocketChannel和阻塞IO套接字之间序列化对象。由于我无法在NIO上使用Serializable/writeObject,因此我想编写代码将对象序列化为ByteArrayOutputStream,然后发送数组长度和数组。发送int作为字节[],然后重新编程int int不工作

发送器功能是

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; 
    } 
} 

的问题是大小(*)总是等于-1393754107时serializedObj.toByteArray()长在我的测试。是316. 我不明白为什么铸造不能正常工作。

+0

铸造?什么铸造? – EJP

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

如果getSocket()结果是在非阻塞模式下的SocketChannel,问题是在这里。您不检查write()的结果。在非阻塞模式下,它可以写入少于ByteBuffer中剩余的字节数;它的确可以写入零字节。

因此,youu并没有写出所有你认为正在编写的数据,所以另一端超出并读取下一个长度字作为正在写入的数据的一部分,并读取下一个数据的一部分作为下一个长度字,并得到一个错误的答案。我很惊讶,它并没有早些时候提供食物。事实上,它可能确实如此,但是你忽视IOExceptions的可悲行为掩盖了它。不要这样做。 日志他们。

所以,你需要循环,直到所有请求的数据已经写入,如果任何write()返回0,则需要直到它激发,增加了一个相当复杂到你的代码,你必须返回到选择环路上OP_WRITE选择同时记住有一个未完成的ByteBuffer还有数据要写入。当你得到OP_WRITE并且写入完成时,你必须注销取消注册对OP_WRITE的兴趣,因为它仅在write()返回零后才感兴趣。

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

+0

现在,调用者的IOException未被屏蔽。它打印堆栈跟踪,但它永远不会抛出。 – Alessandro

+0

write()返回0.始终。 – Alessandro

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