2022更文挑战2-netty源码角度看连接断开问题

127 阅读2分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

netty源码角度看服务器断开连接问题

前文

本文为之前讨论到当网络非常慢时,服务器会主动断开连接。因此从源码角度对该问题进行探索。

相关源码解析

首先需要看一下配置文件,发现其中有pingTimeout以及pingInterval两个参数。根据经验该参数为断开连接的时间设置。因此从源码中继续查找相关引用,找到如下的代码:

public void schedulePingTimeout() {
    SchedulerKey key = new SchedulerKey(Type.PING_TIMEOUT, sessionId);
    disconnectScheduler.schedule(key, new Runnable() {
        @Override
        public void run() {
            ClientHead client = clientsBox.get(sessionId);
            if (client != null) {
                client.disconnect();
                log.debug("{} removed due to ping timeout", sessionId);
            }
        }
    }, configuration.getPingTimeout() + configuration.getPingInterval(), TimeUnit.MILLISECONDS);
}

如上代码分析可以知道,此处进行了定时任务的指定。每次对该方法进行调用时,都会指定一个定时任务,在60+25也就是85秒后,执行socket连接断开的操作。因此找到了断开的源头,下一步只需要找到什么时间该方法被调用即可。继续查看源码,看到了如下的两部分:

image.png 如图可知,第一部分为认证后会进行调用,第二部分大概是消息处理时。认证时也就是第一次连接我们都可以理解,重点来看一下第二部分:

case PING: {
    client.getBaseClient().schedulePingTimeout();
}

case UPGRADE: {
    client.getBaseClient().schedulePingTimeout();
}

case MESSAGE: {
    client.getBaseClient().schedulePingTimeout();
}

case CLOSE:
    client.getBaseClient().onChannelDisconnect();
    break;

如上所示,代码部分进行了部分简化,仅保留了核心内容。当服务器收到客户端的消息、心跳消息、关闭消息、连接升级等消息时,会调用该方法进行连接断开的定时任务。而当收到消息时,也就会将前一个定时任务进行移除操作,这部分此处暂时忽略。所以当连接后,如果客户端没有向服务器发送消息,则需要在85秒内向服务器发送心跳消息,否则连接将断开。

image.png 如上图所示,当客户端消息超过85秒未发送时,产生了服务器连接断开现象。也就解释了当网速比较慢时,客户端消息可能无法成功发送到服务器上,也就是可能导致连接断开问题。

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。