前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >长连接

长连接

原创
作者头像
冰寒火
修改2022-09-28 17:56:21
1.8K0
修改2022-09-28 17:56:21
举报
文章被收录于专栏:软件设计

一、TCP连接

1 三次握手

image.png
image.png

2 四次挥手

image.png
image.png

3 长连接和短连接

短连接的操作步骤是:

建立连接——数据传输——关闭连接…建立连接——数据传输——关闭连接

长连接的操作步骤是:

建立连接——数据传输…(保持连接)…数据传输——关闭连接

正常来说,TCP连接建立后,只要不主动释放,连接会一直存在,所以为了避免无用连接占用资源导致客户端无法建立新连接,就需要保活机制,保活机制在传输层和应用层都有实现。短连接每次交互后会主动释放连接,不需要保活。

二、tcp keep-alive

传输层保活机制

tcp具有保活功能,当tcp服务端回复之后会开启保活定时器,时间一到就会发送探测报文,重复多次后没有得到响应,则关闭连接。这个功能不是tcp的,而是内核支持的。

三、应用层保活机制

以netty举例,通过IdleStateHandler来保活。

1 client

代码语言:java
复制
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    // send heartbeat when read idle.
    if (evt instanceof IdleStateEvent) {
        try {
            NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
            if (logger.isDebugEnabled()) {
                logger.debug("IdleStateEvent triggered, send heartbeat to channel " + channel);
            }
            Request req = new Request();
            req.setVersion(Version.getProtocolVersion());
            req.setTwoWay(true);
            req.setEvent(HEARTBEAT_EVENT);
            channel.send(req);
        } finally {
            NettyChannel.removeChannelIfDisconnected(ctx.channel());
        }
    } else {
        super.userEventTriggered(ctx, evt);
    }
}

2 server

代码语言:java
复制
public class NettyServerHandler extends ChannelDuplexHandler {
    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
    /**
     * the cache for alive worker channel.
     * <ip:port, dubbo channel>
     */
    private final Map<String, Channel> channels = new ConcurrentHashMap<>();

    private final URL url;

    private final ChannelHandler handler;

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
// server will close channel when server don't receive any heartbeat from client util timeout.
        if (evt instanceof IdleStateEvent) {
            NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
            try {
                logger.info("IdleStateEvent triggered, close channel " + channel);
                //关闭
                channel.close();
            } finally {
                NettyChannel.removeChannelIfDisconnected(ctx.channel());
            }
        }
        super.userEventTriggered(ctx, evt);
    }
}

3 IdleStateHandler

该类会开启心跳定时器,如果超时,会立刻注册一个IdleStateEvent

代码语言:java
复制
private void initialize(ChannelHandlerContext ctx) {
    // Avoid the case where destroy() is called before scheduling timeouts.
    // See: https://github.com/netty/netty/issues/143
    switch (state) {
    case 1:
    case 2:
        return;
    default:
         break;
    }

    state = 1;
    initOutputChanged(ctx);
	//开启定时器,
	//客户端每过心跳间隔就立刻发送心跳。
	//服务端定时扫描连接上次读写的时间,如果超时则关闭。
    lastReadTime = lastWriteTime = ticksInNanos();
    if (readerIdleTimeNanos > 0) {
        readerIdleTimeout = schedule(ctx, new ReaderIdleTimeoutTask(ctx),
                readerIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
    if (writerIdleTimeNanos > 0) {
        writerIdleTimeout = schedule(ctx, new WriterIdleTimeoutTask(ctx),
                writerIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
    if (allIdleTimeNanos > 0) {
        allIdleTimeout = schedule(ctx, new AllIdleTimeoutTask(ctx),
                allIdleTimeNanos, TimeUnit.NANOSECONDS);
    }
}

大概处理逻辑是:

  1. client开启定时任务,每隔一个心跳时间就发送一个心跳包,如果多次失败就reconnect。
  2. server开启定时任务来扫描,如果发现某条连接超过若干个心跳没有收到请求,则表示这条连接可能已经结束了,直接close,及时回收掉资源,避免文件句柄的浪费。

四、总结长连接适用场景

  1. 连接频繁,复用连接,可以减少连接创建和释放的开销,适用于客户端比较稳定的场景。个人觉得内部服务之间的RPC比较稳定,适合长连接。与终端用户的交互不太稳定,适合短连接。
  2. 会一直占用文件句柄,需要保活机制及时释放掉断连的连接。

tcp保活机制在内核实现,不太适应应用层,不区分长连接和短连接。可能因为应用层导致无法及时响应请求,但连接还是正常的。tcp保活机制探测时间太长,会持续几个小时,反应不够及时,而应用层保活机制更适合业务开发。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、TCP连接
    • 1 三次握手
      • 2 四次挥手
        • 3 长连接和短连接
        • 二、tcp keep-alive
        • 三、应用层保活机制
          • 1 client
            • 2 server
              • 3 IdleStateHandler
              • 四、总结长连接适用场景
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档