當我們使用Socket開發服務器間相互通信的時候,應該都遇到這個異常,正常情況下,這個是由於客户端和服務器端網絡異常或者強制斷開所產出的異常,具體如下:
java.io.IOException: 遠程主機強迫關閉了一個現有的連接。
at sun.nio.ch.SocketDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
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:380)
at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:253)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1132)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:350)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:151)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
在網上翻了半天沒有找到該異常的處理(屏蔽)方法,於是就自己動手,豐衣足食吧!
通過查看源碼,定位到異常為堆棧信息打印位置:
看名字就能清楚這個是默認的異常監聽類,該類繼承了ExceptionListenerAdapter,而ExceptionListenerAdapter又實現了ExceptionListener 接口,該接口代碼如下:
package com.corundumstudio.socketio.listener;
import io.netty.channel.ChannelHandlerContext;
import java.util.List;
import com.corundumstudio.socketio.SocketIOClient;
public interface ExceptionListener {
void onEventException(Exception e, List<Object> args, SocketIOClient client);
void onDisconnectException(Exception e, SocketIOClient client);
void onConnectException(Exception e, SocketIOClient client);
void onPingException(Exception e, SocketIOClient client);
boolean exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception;
}
如果我們要屏蔽這個異常(堆棧信息),就需要重新實現這個接口,然後覆寫exceptionCaught方法即可。
新建 MyDefaultExceptionListener 類繼承 ExceptionListenerAdapter ,直接上代碼:
@Slf4j
public class MyDefaultExceptionListener extends ExceptionListenerAdapter {
public MyDefaultExceptionListener() {
super();
}
@Override
public void onEventException(Exception e, List<Object> args, SocketIOClient client) {
log.error(e.getMessage());
}
@Override
public void onDisconnectException(Exception e, SocketIOClient client) {
log.error(e.getMessage());
}
@Override
public void onConnectException(Exception e, SocketIOClient client) {
log.error(e.getMessage());
}
@Override
public void onPingException(Exception e, SocketIOClient client) {
log.error(e.getMessage());
}
@Override
public boolean exceptionCaught(ChannelHandlerContext ctx, Throwable e) {
log.error("錯誤:" + e.getMessage());
ctx.close();
return true;
}
}
這個的話,如果出現異常,就不會打印堆棧信息了。
接下來,我們在Socket的初始化配置類裏面設置一下,示例代碼:
com.corundumstudio.socketio.Configuration configuration = new com.corundumstudio.socketio.Configuration();
////其它配置項略///
configuration.setExceptionListener(new MyDefaultExceptionListener());
////其它配置項略///
return new SocketIOServer(configuration);
這裏有個坑需要注意一下,不要在 SocketIOServer 中添加監聽,不起作用。
至此,異常覆寫完成。
注:本文章使用的是 netty-socketio 作為服務端。引入版本為:
<!--socket通信使用-->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.19</version>
</dependency>
完成後日誌最終打印效果如下,再沒有堆棧信息了: