-
Netty
中
IOException: Connection reset by peer
与
ChannelException: null
最近发现系统中出现了很多
IOException: Connection reset by peer
与
ClosedChannelException: null
深入看了看代码
,
做了些测试
,
发现
Connection
reset
会在客户端不知道
channel
被关
闭的情况下
,
触发了
eventloop
的
()
操作抛出
而
ClosedChannelException
一般是由
Netty
主动抛出的
,
在
AbstractChannel
以及
SSLHandler
里都可以看到
ClosedChannel
相关的代码
AbstractChannel
static
final ClosedChannelException
CLOSED_CHANNEL_EXCEPTION =
new ClosedChannelException();
...
static {
CLOSED_CHANNEL_
ckTrace(_ST
ACK_TRACE);
NOT
_YET_CONNECTED_ckTrace(
_STACK_TRACE);
}
...
@Override
public void
write
(Object msg,
ChannelPromise promise) {
ChannelOutboundBuffer outboundBuffer
=
ndBuffer;
if
(outboundBuffer ==
null
) {
//
If the outboundBuffer is null we know the channel
was
closed and so
//
need to fail the future right away. If it is not
null the
handling of the rest
// will be done in flush0()
//
See /netty/netty/issues/2362
safeSetFailure(promise,
CLOSED_CHANNEL_EXCEPTION);
//
release message now to prevent resource-
leak
e(msg);
return;
}
sage(msg, promise);
}
在代码的许多部分
,
都会有这个
ClosedChannelException,
大概的意思是说在
channel
close
以后
,
如果还调用了
write
方法
,
则会将
write
的
future
设置为
failure,
并将
cause
设置为
ClosedChannelException,
同样
SSLHandler
中也类似
-----------------
回到
Connection
reset by peer,
要模拟这个情况比较简单
,
就是在
server
端设置一个在
channelActive
的时候就
close
channel
的
handler.
而在
client
端则写一个
Connect
成
功后立即发送请求数据的
listener.
如下
client
public static
void main(String[] args) throws IOException,
InterruptedException {
Bootstrap b
=
new
Bootstrap();
(new NioEventLoopGroup())
.channel()
.handler(new ChannelInitializer
() {
@Override
protected void
initChannel(NioSocketChannel ch)
throws
Exception {
}
});
t(
,
8090
).addListener(new
ChannelFutureListener() {
@Override
public void
operationComplete(ChannelFuture future) throws
Exception {
if
(ess()) {
l().
write
(().writeBytes(
.getBytes
()));
l().flush();
}
}
});
server
public class
SimpleServer {
public static
void main(String[] args) throws Exception {
EventLoopGroup bossGroup
= new
NioEventLoopGroup(
1
);
EventLoopGroup workerGroup
=
new NioEventLoopGroup();
ServerBootstrap b
=
new ServerBootstrap();
(bossGroup, workerGroup)
.channel()
.option(_REUSEADDR,
true
)
.childHandler(new ChannelInitializer
()
{
@Override
protected void
initChannel(NioSocketChannel ch)
throws
Exception {
ne().addLast(new
SimpleServerHandler());
}
});
p>
(
8090
).
s
ync
().channel().closeFuture().
sync
();
}
}
public class
SimpleServerHandler extends
ChannelInboundHandlerAdapter {
@Override
public void
channelActive(ChannelHandlerContext ctx) throws
Exception {
l().close().
sync
();
}
@Override
public void
channelRead(ChannelHandlerContext ctx, final
Object msg)
throws Exception {
n(
123
);
}
@Override
public void
channelInactive(ChannelHandlerContext ctx) throws
Exception
{
n(
);
}
}
这种情况之所以能触发
connection reset by peer
异常
,
是因为
connect
成功以后
, client
段先会触发
connect
成功的
listener,
这个时候
server
段虽然断开了
channel,
也触发
channel
断开的事件
(
它会触发一个客户端
read
事件
,
但是这个
read
会返回
-1, -1
代
表
channel
关闭
,
client
的
channelInactive
跟
channel
active
状态的改变都是在这时
发生的
),
但是这个事件是在
connect
成功的
listener
之后执行
,
所以这个时候
listener
里的
channel
并不知道自己已经断开
,
它还是会继续进行
write
跟
flush
操作
,
在调用
flush
后
, eventloop
会进入
OP_READ
事件里
,
这时候
()
就会抛出
connection
reset
异常
. eventloop
代码如下
NioEventLoop
private static void
processSelectedKey(SelectionKey k,
AbstractNioChannel
ch) {
final NioUnsafe unsafe
=
();
if
(!
d()) {
// close the channel if the key is not
valid anymore
(omise());
return;
}
try {
int
readyOps =
ps();
//
Also check for readOps of 0 to workaround possible
JDK bug
which may otherwise lead
// to a spin loop
if
((readyOps & (_READ |
_ACCEPT)) !=
0
||
readyOps ==
0
) {
();
-
-
-
-
-
-
-
-
-
上一篇:公共场所双语标识翻译标准
下一篇:oracle安装及使用中出现的问题及解决 (1)