Search code examples
javamultithreadingsocketsionetty

netty DefaultChannelPipeline exceptionCaught


Unfortunately, I don't understand this output from the netty server:

BUILD SUCCESSFUL
Total time: 3 seconds
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler channelRegistered
INFO: [id: 0xcad25a31] REGISTERED
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler bind
INFO: [id: 0xcad25a31] BIND(0.0.0.0/0.0.0.0:4454)
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler channelActive
INFO: [id: 0xcad25a31, /0:0:0:0:0:0:0:0:4454] ACTIVE
Jul 27, 2014 2:04:59 AM io.netty.handler.logging.LoggingHandler logMessage
INFO: [id: 0xcad25a31, /0:0:0:0:0:0:0:0:4454] RECEIVED: [id: 0xff40b8a2, /127.0.0.1:37558 => /127.0.0.1:4454]
Jul 27, 2014 2:04:59 AM net.bounceme.dur.netty.ServerHandler <init>
INFO: starting..
Jul 27, 2014 2:04:59 AM io.netty.channel.DefaultChannelPipeline$TailContext exceptionCaught
WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 2901213193 - discarded
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:501)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)
    at io.netty.handler.codec.serialization.ObjectDecoder.decode(ObjectDecoder.java:68)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:343)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:241)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:149)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:125)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
    at java.lang.Thread.run(Thread.java:744)

^Cthufir@dur:~/NetBeansProjects/AgentServer$ 
thufir@dur:~/NetBeansProjects/AgentServer$ 

Presumably the netty-based server is complaining that it's receiving bad data in some respect?

client code:

package net.bounceme.dur.client.gui;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import net.bounceme.dur.client.jdbc.Title;

public final class ApplicationDriver {

    private static final Logger log = Logger.getLogger(ApplicationDriver.class.getName());
    private TitlesGUI gui = null;
    private Handler handler = null;

    public ApplicationDriver() throws IOException, ClassNotFoundException {
        handler = new FileHandler("application.log");
        handler.setFormatter(new SimpleFormatter());
        log.setLevel(Level.INFO);
        log.addHandler(handler);
        log.info("starting log..");
        MyProps p = new MyProps();
        String host = p.getHost();
        int port = p.getServerPort();
        guiThread();
        readWrite(host, port);
    }

    private void guiThread() {
        Thread g;
        g = new Thread() {
            @Override
            public void run() {
                try {
                    gui = new TitlesGUI();
                } catch (IOException ex) {
                    log.severe(ex.toString());
                }
                gui.setVisible(true);
            }
        };
        g.start();
    }

    public static void main(String... args) throws IOException, ClassNotFoundException {
        new ApplicationDriver();
    }

    private void readWrite(final String host, final int port) throws IOException {
        Thread inputOutput;
        final Socket socket = new Socket(host, port);
        inputOutput = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
                            ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
                        gui.setTitle((Title) objectInputStream.readObject());
                        Thread.sleep(1000);
                    } catch (IOException | ClassNotFoundException | InterruptedException ex) {
                        log.severe(ex.toString());
                    }
                }
            }

        };
        inputOutput.start();
    }
}

is it a problem that the client is using regular sockets instead of netty? Both on the client and server side POJO's are being sent. (The Title class is serializable and the serialVersionUID values match up.)

a method from the GUI client (which is a bit large, it's a Netbeans Swing JFrame):

public void setTitle(Title title) {
    this.title = title;
    text.setText(title.toString());
}

the point of the above method is for something to send objects to the GUI, which is then updated accordingly. Similarly, I want to fire updates, or other-wise wire the GUI to socket i/o.

I don't really understand the output from the netty server. Is it a problem that the server uses netty while the client uses sockets? Both use the same POJO, with the serialVersionUID value. Here's the netty handler code:

package net.bounceme.dur.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Logger;
import net.bounceme.dur.jdbc.Title;

public class ServerHandler extends SimpleChannelInboundHandler<Title> {

    private static final Logger log = Logger.getLogger(ServerHandler.class.getName());

    public ServerHandler() {
        log.info("starting..");
    }

    @Override
    public boolean acceptInboundMessage(Object msg) throws Exception {
        log.info(msg.toString());
        return true;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info(msg.toString());
        ctx.write(new Title());
    }

    @Override
    protected void channelRead0(ChannelHandlerContext chc, Title title) throws Exception {
        log.info(title.toString());
        chc.write(new Title());
    }
}

Apparently, none of the server handler code is executed, as everything explodes immediately after the client connects.

server code:

package net.bounceme.dur.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.security.cert.CertificateException;
import java.util.logging.Logger;
import javax.net.ssl.SSLException;

public final class Server {

    private static final Logger log = Logger.getLogger(Server.class.getName());

    public static void main(String[] args) throws Exception {
        MyProps p = new MyProps();
        int port = p.getServerPort();
        new Server().startServer(port, false);
    }

    private void startServer(int port, boolean ssl) throws CertificateException, SSLException, InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(
                                    new ObjectEncoder(),
                                    new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
                                    new ServerHandler());
                        }
                    });
            b.bind(port).sync().channel().closeFuture().sync();
            log.info("connected!");
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

Solution

  • The TooLongFrameException raised by LengthFieldBasedFrameDecoder means one of the following:

    • The remote peer sent a very large message, which exceeds the limit. The default maximum length of a message is 1 MiB. If you expect to receive a message larger than that, specify an alternative maximum length when you construct a LengthFieldBasedFrameDecoder.
    • You passed wrong parameters to LengthFieldBasedFrameDecoder so that it is decoding a wrong place in your message. In this case, you'd better re-read the Javadoc of LengthFieldBasedFrameDecoder to specify the correct values for you.