-->

Netty ObjectDecoder throws java.io.StreamCorrupted

2020-07-30 03:57发布

问题:

I've an unusual problem that's causing me to tear my hair out. I have a Netty Client/Server setup. The server sends a command object to the client. The client then sends each of the binary commands found in the command object to a device attached to it's local serial port. The answers to each command ( a binary string) is stored within the command object and when all the commands have been executed, the command object is returned to the server. So I'm using the ObjectEncoder and ObjectDecoder in both my client and Server pipelines.

I have one specific, repeatable case where the server throws "java.io.StreamCorruptedException: unexpected end of block data" (stack trace below) when a specific command object is returned to the server. I'm using Netty 3.2.7-Final on both the server and client and I'm using Oracle Java 1.7.0_02 on both client and server.

What is really doing my head in is that if I run the client & server locally under Windows 7, then the job runs correctly. If I run the server remotely on a Debian Linux system then the specific job runs correctly. However, when ever I run the server on a Linux CentOS 6 system, the job fails every time with the exception. (The client has to run in a Windows environment)

Any suggestions as to how to debug this further would be very welcome. I've looked at extending ObjectEncoder so I can dump the serialized object to disk to see what is being put on the wire but I can't work out how to get the contents of the ChannelBuffer returned by the encode method.

java.io.StreamCorruptedException: unexpected end of block data
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1369)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
    at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:498)
    at java.lang.Throwable.readObject(Throwable.java:913)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:991)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1866)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
    at java.util.ArrayList.readObject(ArrayList.java:733)
    at sun.reflect.GeneratedMethodAccessor70.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:991)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1866)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
    at org.jboss.netty.handler.codec.serialization.ObjectDecoder.decode(ObjectDecoder.java:129)
    at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:282)
    at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:214)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:351)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

回答1:

Since the problem occurs while decoding,

You can hex-dump of the received channel buffer to a log before decoding and analyse it later. You have to have your own version of the ObjectDecoder like

    @Override
protected Object decode(
        ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {

    ChannelBuffer frame = (ChannelBuffer) super.decode(ctx, channel, buffer);
    if (frame == null) {
        return null;
    }


    logger.debug("Hex dump of object frame [" + ChannelBuffers.hexDump(frame) + "]");

    return new CompactObjectInputStream(
            new ChannelBufferInputStream(frame), classResolver).readObject();
}