I want to write raw bytes to a netty Channel. I thought I could do this by first creating a ChannelBuffer, filling it with bytes (coming from, say, a Kryo serializer), and then writing that ChannelBuffer to the netty Channel.
Here is the relevant code, where I’m simply filling some bytes into a ChannelBuffer in the ctor and trying to send it upon connection:
/**
* Handler implementation for the object echo client. It initiates the
* ping-pong traffic between the object echo client and server by sending the
* first message to the server.
*/
public class ObjectEchoClientHandler extends SimpleChannelUpstreamHandler {
private final ChannelBuffer firstMessage;
/**
* Creates a client-side handler.
*/
public ObjectEchoClientHandler(int firstMessageSize) {
if (firstMessageSize <= 0) {
throw new IllegalArgumentException(
"firstMessageSize: " + firstMessageSize);
}
firstMessage = ChannelBuffers.buffer(8192);
for (int i = 0; i < firstMessageSize; i++) {
firstMessage.writeByte(i % 256);
}
}
@Override
public void channelConnected(
ChannelHandlerContext ctx, ChannelStateEvent e) {
// Send the first message if this handler is a client-side handler.
// e.getChannel().write(firstMessage);
Channels.write(ctx, e.getFuture(), firstMessage);
}
}
This doesn’t seem to work, as it throws this exception:
java.io.NotSerializableException: org.jboss.netty.buffer.BigEndianHeapChannelBuffer
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at org.jboss.netty.handler.codec.serialization.ObjectEncoder.encode(ObjectEncoder.java:80)
at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream(OneToOneEncoder.java:61)
at org.jboss.netty.channel.Channels.write(Channels.java:626)
at org.jboss.netty.channel.Channels.write(Channels.java:587)
at ca.gsimard.spacecraft.client.ObjectEchoClientHandler.channelConnected(ObjectEchoClientHandler.java:83)
at ca.gsimard.spacecraft.client.ObjectEchoClientHandler.handleUpstream(ObjectEchoClientHandler.java:75)
at org.jboss.netty.channel.Channels.fireChannelConnected(Channels.java:227)
at org.jboss.netty.channel.socket.nio.NioWorker$RegisterTask.run(NioWorker.java:784)
at org.jboss.netty.channel.socket.nio.NioWorker.processRegisterTaskQueue(NioWorker.java:250)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:192)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
I’m sure this is dead trivial and probably the wrong way of doing it, because I can’t seem to find anyone who had the same error as this. I’m using Netty 3.3.0 right now.
I can get this to work by creating a properly sized byte[] and copying the contents of the ChannelBuffer to it, but I would have liked a more direct solution that avoids useless byte copying.
byte[] array = new byte[firstMessage.writerIndex()];
firstMessage.readBytes(array);
e.getChannel().write(array);
Thanks for any pointers !
Looking at your stack trace, I observed these two lines:
What this means to me is that your pipeline contains an ObjectEncoder which is attempting to serialize a ChannelBuffer. Since your objects have already been encoded by Kryo, you don’t need the ObjectEncoder.
Or put differently (without Kryo), a ChannelBuffer should be the output of the ObjectEncoder and your object should be the input.
Your best bet is to write a new ChannelHandler that uses Kryo to encode your objects. You may find some added efficiencies when Kryo does it’s job as a handler in the Netty pipeline.