nflacco
nflacco

Reputation: 5082

Basic Netty echo server - string encoder error?

This is my first time using Netty and I'm having trouble making a simple echo server! I looked at docs and it says to use the string encoder and decoder, which I am not using properly apparently. For the framedecoder, I'd like to use the header messages with one byte length, but that doesn't seem to be working either due to the string issue. I assume my implementation of the PipelineFactory is messed up.

Bonus Question:

Because I'm stupid and ambitious, I tried implementing a timeout/heartbeat handler. That didn't work either.

Here are the console output and java code:

Console:

>>telnet localhost 6969
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
>>3
Connection closed by foreign host.

Java Console:

Starting server on 6969
channelConnected
channelDisconnected
java.lang.IllegalArgumentException: unsupported message type: class java.lang.String
    at org.jboss.netty.channel.socket.nio.SocketSendBufferPool.acquire(SocketSendBufferPool.java:51)
    at org.jboss.netty.channel.socket.nio.NioWorker.write0(NioWorker.java:455)
...

Server.java

public class Server {

    public static void main(String[] args) throws Exception {
        ChannelFactory factory =
                new NioServerSocketChannelFactory(
                        Executors.newCachedThreadPool(),
                        Executors.newCachedThreadPool());

        ServerBootstrap bootstrap = new ServerBootstrap(factory);

        Timer timer = new HashedWheelTimer();

        bootstrap.setPipelineFactory(new MyPipelineFactory(timer) {
            public ChannelPipeline getPipeline() {
                return Channels.pipeline(new ServerHandler());
            }
        });

        bootstrap.setOption("child.tcpNoDelay", true);
        bootstrap.setOption("child.keepAlive", true);

        bootstrap.bind(new InetSocketAddress(6969));
        System.out.println("Starting server on 6969");
    }
}

ServerHandler.java

public class ServerHandler extends SimpleChannelHandler {

    @Override
    public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){
        Channel ch = e.getChannel();
        System.out.println("channelConnected");
    }

    @Override
    public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e){
        Channel ch = e.getChannel();
        System.out.println("channelDisconnected");
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
        String msg = (String) e.getMessage();
        e.getChannel().write("Did you say '" + msg + "'?\n");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
        e.getCause().printStackTrace();
        Channel ch = e.getChannel();
        ch.close();
    }
}

MyPipelineFactory.java

public class MyPipelineFactory implements ChannelPipelineFactory {

    private final Timer timer;
    private static ChannelHandler idleStateHandler;

    public MyPipelineFactory(Timer t) {
        this.timer = t;
        //this.idleStateHandler = new IdleStateHandler(timer, 5, 20, 0); // timer must be shared
    }

    public ChannelPipeline getPipeline() {
        // create default pipeline from static method
        ChannelPipeline pipeline = Channels.pipeline();

        // Decoders
        int maxFrameLength = 1024;
        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(maxFrameLength, Delimiters.lineDelimiter()));
        //pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(maxFrameLength,0,1)); // get header from message
        pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));

        // Encoders
        pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

        // Idle state handling- heartbeat
        //pipeline.addLast("idleStateHandler", idleStateHandler);

        return pipeline;
    }

}

Bonus, because I'm stupid and want to get in over my head...

HeartbeatHandler.java

public class HeartbeatHandler extends IdleStateAwareChannelHandler {

    @Override
    public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
        if (e.getState() == IdleState.READER_IDLE) {
            System.out.println("Reader idle, closing channel");
            e.getChannel().close();
        }
        else if (e.getState() == IdleState.WRITER_IDLE) {
            System.out.println("Writer idle, sending heartbeat");
            e.getChannel().write("heartbeat"); // 
        }
    }
}

Upvotes: 2

Views: 6928

Answers (1)

Norman Maurer
Norman Maurer

Reputation: 23567

It's because you mess up the ChannelPipeline.

You use:

 bootstrap.setPipelineFactory(new MyPipelineFactory(timer) {
        public ChannelPipeline getPipeline() {
            return Channels.pipeline(new ServerHandler());
        }
    });

What you would need todo is modify the MyPipelineFactory class and add your ServerHandler in there. Then just set it like:

 bootstrap.setPipelineFactory(new MyPipelineFactory(timer));

Then everything should work. Even your timeout stuff ;)

Upvotes: 1

Related Questions