写入时刷新Netty通道失败,刷新太多太快

时间:2015-08-12 13:44:22

标签: java netty

当我写一个制作人将消息发布到我的服务器时。我见过这个:

java.io.IOException: Connection reset by peer
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:384)
at io.netty.buffer.UnpooledUnsafeDirectByteBuf.setBytes(UnpooledUnsafeDirectByteBuf.java:447)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:881)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:242)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:119)
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:111)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)

我四处搜索并被告知由于频道已关闭。 但是,在我的代码中。当我的频道池破坏频道时,我只是关闭了我的频道。
这是我的代码:

public static class ChannelFactory implements PoolableObjectFactory<Channel> {

    private final Bootstrap bootstrap;
    private String host;
    private int port;

    public ChannelFactory(Bootstrap bootstrap, String host, int port) {
        this.bootstrap = bootstrap;
        this.host = host;
        this.port = port;
    }

    @Override
    public Channel makeObject() throws Exception {
        System.out.println("Create new channel!!!");
        bootstrap.validate();
        return bootstrap.connect(host, port).channel();
    }

    @Override
    public void destroyObject(Channel channel) throws Exception {
        ChannelFuture close = channel.close();
        if (close.isSuccess()) {
            System.out.println(channel + " close successfully");
        }
    }

    @Override
    public boolean validateObject(Channel channel) {
        System.out.println("Validate object");
        return (channel.isOpen());
    }

    @Override
    public void activateObject(Channel channel) throws Exception {
        System.out.println(channel + " is activated");
    }

    @Override
    public void passivateObject(Channel channel) throws Exception {
        System.out.println(channel + " is passivated");
    }

    /**
     * @return the host
     */
    public String getHost() {
        return host;
    }

    /**
     * @param host the host to set
     * @return
     */
    public ChannelFactory setHost(String host) {
        this.host = host;
        return this;
    }

    /**
     * @return the port
     */
    public int getPort() {
        return port;
    }

    /**
     * @param port the port to set
     * @return
     */
    public ChannelFactory setPort(int port) {
        this.port = port;
        return this;
    }

}

这是我的跑步者:

public static class Runner implements Runnable {

    private Channel channel;
    private ButtyMessage message;
    private MyChannelPool channelPool;

    public Runner(MyChannelPool channelPool, Channel channel, ButtyMessage message) {
        this.channel = channel;
        this.message = message;
        this.channelPool = channelPool;
    }

    @Override
    public void run() {
        channel.writeAndFlush(message.content()).syncUninterruptibly().addListener(new ChannelFutureListener() {

            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                channelPool.returnObject(future.channel());
            }
        });
    }

}

我的主要:

public static void main(String[] args) throws InterruptedException {

    final String host = "127.0.0.1";
    final int port = 8080;
    int jobSize = 100;
    int jobNumber = 10000;
    final Bootstrap b = func(host, port);

    final MyChannelPool channelPool = new MyChannelPool(new ChannelFactory(b, host, port));

    ExecutorService threadPool = Executors.newFixedThreadPool(1);
    for (int i = 0; i < jobNumber; i++) {
        try {
            threadPool.execute(new Runner(channelPool, channelPool.borrowObject(), new ButtyMessage()));
        } catch (Exception ex) {
            System.out.println("ex = " + ex.getMessage());
        }
    }
}

ButtyMessage扩展ByteBufHolder
在我的Runner课程中,如果我在writeAndFlush之后睡觉(10)它运行得很好。但我不想回答睡眠问题。所以我使用ChannelFutureListener,但结果很糟糕。如果我发送大约1000到10.000条消息,它将崩溃并抛出异常。有什么方法可以避免这种情况吗?

谢谢大家。
对不起我的解释和我的英语:)

1 个答案:

答案 0 :(得分:1)

您有几个问题可以解释这一点。其中大多数都与错误使用异步操作和将来使用有关。

  • 我不知道它是否与您的问题有关,但如果您真的想在频道真正关闭时进行打印,那么您必须等待未来,因为未来{{1 (或任何其他操作)立即返回,而不等待真正的关闭。因此,您的测试close()应始终为假。

    if (close.isSuccess())

但是,我认为它仅用于调试目的,不是强制性的。

  • 另一个:你向游泳池发送一个尚未连接的频道(可以解释你的睡眠(10)?)。您必须等待public void destroyObject(final Channel channel) throws Exception { channel.close().addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture close) { if (close.isSuccess()) { System.out.println(channel + " close successfully"); } } }); }

    connect()
  • 第三个:使用public Channel makeObject() throws Exception { System.out.println("Create new channel!!!"); //bootstrap.validate(); // this is implicitely called in connect() ChannelFuture future = bootstrap.connect(host, port).awaitUninterruptibly(); if (future.isSuccess()) { return future.channel(); } else { // do what you need to do when the connection is not done } } 验证连接的频道可能会更好:

    isActive()
  • 第四个问题:在你的跑步者中,你错误地等待未来,而你却不应该。您可以删除@Override public boolean validateObject(Channel channel) { System.out.println("Validate object"); return channel.isActive(); // instead of isOpen() } ,其余部分保留原样。

    syncUninterruptibly()
  • 最后,我想你知道你的测试是完全顺序的(池中有1个线程),这样每个客户端都会在同一个频道上重复使用?

您是否可以尝试更改4个点以查看它是否可以解决您的问题?

在请求者评论

之后

编辑:

对于@Override public void run() { Channel.writeAndFlush(message.content()).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { channelPool.returnObject(future.channel()); } }); } ,我没有仔细阅读。如果要阻止写入,则不需要额外的syncUntinterruptibly(),因为一旦同步结束,将来就会完成。因此,您可以在同步后直接将addListener作为下一个命令调用。

所以你应该这样写,更简单。

channelPool.returnObject

对于 @Override public void run() { Channel.writeAndFlush(message.content()).syncUntinterruptibly(); channelPool.returnObject(future.channel()); } ,它将在连接完成后立即调用(所以从fireChannelActive开始调用,将来的某个时间)。此外,一旦断开连接(正如您在异常中注意到的那样),通道就不再可用,必须从零重新创建。所以我建议使用isActive,这样,如果不活动,它将使用destroyObject删除...

查看频道状态模型here