0

我正在解决这个非常奇怪的问题,我希望有人可以向我解释原因。

我有这段代码通过套接字连接从文件传输数据。

    byte[] chunk = new byte[Constants.TRANSFER_CHUNK_SIZE];
    try (InputStream fileInputStream = new FileInputStream(sourceFile); BufferedInputStream buffFileInputStream = new BufferedInputStream(fileInputStream)) {
        while (offset < sourceFileSize) {
            int numBytes = buffFileInputStream.read(chunk, 0, Constants.TRANSFER_CHUNK_SIZE);
            Message chunkMessage = new Message(MessageType.SPM_TRANSFER_CHUNK, numBytes, null, chunk);
            this.sendMessage(chunkMessage);
        }
    }

方法 sendMessage 没有做任何特别的事情,只是通过 ObjectOutputStream 发送对象:

private void sendMessage(Message message) {
    try {
       this.conOutputStream.writeObject(message);
       this.conOutputStream.flush();
    } catch (IOException ex) {
            ......
    }
}

Message 类本身如下所示:

public class Message implements Serializable {

protected final MessageType type;
protected final int intValue;
protected final String stringValue;
protected byte[] data;
protected final long longValue;

public Message(MessageType type, int intValue, long longValue, String stringValue, byte[] data) {
    this.type = type;
    this.intValue = intValue;
    this.stringValue = stringValue;
    this.data = data;
    this.longValue = longValue;
}

................

}

当我在发送端打印出块数组时,数据正常,但在接收端我总是从第一个块接收数据,比如(只打印前三个字节):

RC: 73 68 51
RC: 73 68 51
RC: 73 68 51
RC: 73 68 51
.......

我已经知道的:

  • 问题不在运输途中。
  • 在该while循环的每个循环中创建一个新数组可以解决这个问题(但是内存效率低,这就是我改变它的原因。)

提前致谢。

4

2 回答 2

0
public SyncPlaneMessage(MessageType type, int intValue, long longValue, String stringValue, byte[] data) {
    // ...
    this.data = data;
    // ...
}

您正在保存对传入数组的引用。如果该数组在构造函数调用后发生更改,那么this.data. 这就是为什么创建数组的副本可以解决问题。

复制数组确实会占用更多内存,但您有什么选择?制作副本的正确位置至少是在构造函数中,而不是在while循环中。

this.data = Arrays.copyOf(data, data.length);
于 2013-03-28T13:26:57.770 回答
0

终于找到了解决这个问题的办法。此问题是由序列化缓存引起的。ObjectOutputStream 不会发送相同的对象(即使已更改),如果它之前已发送到相同的流。

在发送每条消息之前重置ObjectOutputStream解决了我的问题,可能会有一些性能损失,但问题解决了。现在ObjectOutputStream总是发送新数据。

所以在我的例子中,我修改了方法 sendMessage(),所以它现在在发送消息对象之前重置ObjectOutputStream 。

private void sendMessage(Message message) {
    try {
       this.conOutputStream.reset();
       this.conOutputStream.writeObject(message);
       this.conOutputStream.flush();
    } catch (IOException ex) {
            ......
    }
}
于 2013-04-16T08:43:11.440 回答