netty DefaultChannelPipeline exceptionCaught

时间:2014-07-27 09:23:48

标签: java multithreading sockets io netty

不幸的是,我不理解netty服务器的输出:

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$ 

据推测,基于netty的服务器抱怨它在某些方面收到了错误的数据?

客户代码:

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

客户端使用常规套接字而不是netty是一个问题吗?客户端和服务器端都在发送POJO。 (Title类是可序列化的,并且serialVersionUID值匹配。)

来自GUI客户端的方法(有点大,它是一个Netbeans Swing JFrame):

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

上述方法的目的是让某些东西将对象发送到GUI,然后相应地更新。同样,我想触发更新,或者其他方式将GUI连接到socket i / o。

我不太了解netty服务器的输出。服务器在客户端使用套接字时使用netty是一个问题吗?两者都使用相同的POJO和serialVersionUID值。这是netty处理程序代码:

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

显然,没有一个服务器处理程序代码被执行,因为一切都在客户端连接后立即爆炸。

服务器代码:

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

1 个答案:

答案 0 :(得分:6)

TooLongFrameException引发的LengthFieldBasedFrameDecoder表示以下其中一项:

  • 远程对等方发送了一条非常大的消息,超过了限制。消息的默认最大长度为1 MiB。如果您希望收到大于该消息的消息,请在构建LengthFieldBasedFrameDecoder时指定备用最大长度。
  • 您将错误的参数传递给LengthFieldBasedFrameDecoder,以便它正在解码您邮件中的错误位置。在这种情况下,您最好重新阅读LengthFieldBasedFrameDecoder的Javadoc,为您指定正确的值。