Stories

Detail Return Return

java.io.IOException: 遠程主機強迫關閉了一個現有的連接。異常堆棧信息問題處理(屏蔽)!【轟隆隆原創】 - Stories Detail

當我們使用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

Add a new Comments

Some HTML is okay.