当我们使用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)

在网上翻了半天没有找到该异常的处理(屏蔽)方法,于是就自己动手,丰衣足食吧!
通过查看源码,定位到异常为堆栈信息打印位置:
image.png

看名字就能清楚这个是默认的异常监听类,该类继承了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>

完成后日志最终打印效果如下,再没有堆栈信息了:
image.png


轰隆隆
38 声望0 粉丝

一直在奔跑...