Основной эхо-сервер Netty - ошибка кодировщика строк? - PullRequest
2 голосов
/ 14 февраля 2012

Я впервые использую Netty, и у меня возникают проблемы при создании простого эхо-сервера! Я посмотрел на документы, и там написано, что нужно использовать строковый кодировщик и декодер, который я, очевидно, не использую должным образом. Для кодировщика кадров я хотел бы использовать заголовочные сообщения длиной в один байт, но, похоже, это тоже не работает из-за проблемы со строкой. Я предполагаю, что моя реализация PipelineFactory испорчена.

Бонусный вопрос:

Поскольку я глупый и амбициозный, я попытался реализовать обработчик timeout / heartbeat . Это тоже не сработало.

Вот вывод консоли и код Java:

Консоль

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

Консоль Java:

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

}

Бонус, потому что я тупой и хочу залезть мне на голову ...

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"); // 
        }
    }
}

1 Ответ

1 голос
/ 14 февраля 2012

Это потому, что вы испортили ChannelPipeline.

Вы используете:

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

Вам нужно изменить класс MyPipelineFactory и добавить туда свой ServerHandler. Затем просто установите его как:

 bootstrap.setPipelineFactory(new MyPipelineFactory(timer));

Тогда все должно работать. Даже ваши вещи тайм-аут;)

...