zoukankan      html  css  js  c++  java
  • 连接管理 与 Netty 心跳机制

    一、前言

    踏踏实实,动手去做,talk is cheap, show me the code。先介绍下基础知识,然后做个心跳机制的Demo。

    二、连接

    长连接:在整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接;短连接:每次请求,都新建一个Socket,处理完一个请求就直接关闭掉Socket。所以,其实区分二者就是:整个客户和服务端的通讯过程是利用一个Socket还是多个Socket进行的。一般,长连接多用于数据发送频繁,点对点的通讯。因为TCP连接都需要握手,这很花费时间,有时建立连接的时间有可能比业务传输的时间要多。

    客户端不主动断开连接,并不是说连接就不会断。比如:客户端突然断电、网线故障、空闲的Socket被防火墙自动关闭、系统崩溃等,服务端无法检测到连接的断开,因此需要对长连接进行管理。

    保活的两种方式:

    ①TCP协议自带的keep-alive功能

    ★系统内核自动替上层做好

    ★内核层面计时器相比上册应用更高效

    ★数据包更紧凑,数据量更小

    ★默认的心跳时间是2小时,依赖操作系统实现不够灵活

    ②应用层的keep-alive,一般叫做心跳包机制

    (TCP长连接中,客户端和服务端定时向对方发送数据包通知自己还在线,保证连接有效性的机制)

    ★完全使用业务层面的心跳保活机制

    ★更大灵活性,可以自己控制检测的参数,如检测的时间间隔、检测的方式等

    ★不依赖协议,心跳包同时适用于TCP和UDP

    因此如果你们能确定更换协议的可能性非常小, 同时只是需要检活的功能, 那么用协议自带的就可以了, 使用简单而且高效。

    三、Netty 心跳连接

    1.基于 IdleStateHandler

    首先我们要知道,在服务器和客户端之间,一段时间内没有数据交互时,即处于Idle状态。下面是通过Netty IdleStateHandler来实现心跳机制。

    使用方法:

    (code摘自Netty api 文档  https://netty.io/4.0/api/io/netty/handler/timeout/IdleStateHandler.html )

     1  public class MyChannelInitializer extends ChannelInitializer<Channel> {
     2       @Override
     3      public void initChannel(Channel channel) {
     4          channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(60, 30, 0));
    // IdleStateHandler的构造方法有三个参数,监控读、监控写、监控读与写、触发心跳机制的时间间隔(单位,秒)
    // 0 表示 disable
    5 channel.pipeline().addLast("myHandler", new MyHandler()); 6 } 7 } 8 9 // Handler should handle the IdleStateEvent triggered by IdleStateHandler. 10 public class MyHandler extends ChannelDuplexHandler { 11 @Override 12 public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 13 if (evt instanceof IdleStateEvent) { 14 IdleStateEvent e = (IdleStateEvent) evt; 15 if (e.state() == IdleState.READER_IDLE) { 16 ctx.close(); 17 } else if (e.state() == IdleState.WRITER_IDLE) { 18 ctx.writeAndFlush(new PingMessage()); 19 } 20 } 21 } 22 } 23 24 ServerBootstrap bootstrap = ...; 25 ... 26 bootstrap.childHandler(new MyChannelInitializer()); 27 ... 28

     2.基于keep-alive

    分别开启keep-alive功能即可

    服务端:

    b.group(group).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
                        .childOption(ChannelOption.SO_KEEPALIVE, true).handler(new LoggingHandler(LogLevel.INFO))
                        .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {

    客户端:

    bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE, true)
                        .remoteAddress(new InetSocketAddress(host, port)).handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel channel) throws Exception {
                                channel.pipeline().addLast(new EchoClientHandler());
                            }
                        });

    参考资料:

    https://www.cnblogs.com/my_life/articles/4045696.html

    https://blog.csdn.net/u013967175/article/details/78591810

    https://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/

    https://blog.csdn.net/linuu/article/details/51404264

  • 相关阅读:
    获取文件夹下的所有文件名,并修改某些文件名 Alec
    生成XML文件,并保存到本地文件 Alec
    按Enter键起到Tab键的效果 Alec
    网站底部浮动js Alec
    NET Framework4.0注册 Alec
    从FTP上下载文件到本地 Alec
    生成txt日志操作文件 Alec
    不使用第三个变量,实现两个变量值的交换 Alec
    生成指定位数的回文素数 Alec
    单击gridview某一列弹出详细信息 Alec
  • 原文地址:https://www.cnblogs.com/lihao007/p/10505645.html
Copyright © 2011-2022 走看看