当我写一个制作人将消息发布到我的服务器时。我见过这个:
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条消息,它将崩溃并抛出异常。有什么方法可以避免这种情况吗?
谢谢大家。
对不起我的解释和我的英语:)
答案 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。