基于netty的企业即时通讯系统的设计与实现-心跳机制
cookqq ›博客列表 ›netty

基于netty的企业即时通讯系统的设计与实现-心跳机制

2016-04-05 20:45:27.0|分类: netty|浏览量: 3370

摘要: 客户端和服务器建立了长连接,一个客户端只能建立一个长连接,如果有成千上万个客户端与服务器建立连接,服务器就会保持同数量的长连接。服务器保持大量长连接需要消耗大量资源,同时服务器也要处理消息,服务器端的压力还是很大的。

客户端和服务器建立了长连接,一个客户端只能建立一个长连接,如果有成千上万个客户端与服务器建立连接,服务器就会保持同数量的长连接。服务器保持大量长连接需要消耗大量资源,同时服务器也要处理消息,服务器端的压力还是很大的。

国内的移动网络有一个特点,不稳定,因为我们不知道什么时候会掉线,还有延迟是非常大的,移动网络的不稳定和高延迟。

如果客户端与服务器建立长连接之后,由于网络原因,客户端与服务器这个长连接断开,但是服务器端没有收到长连接断开的命令,还会认为这个长连接连接活跃,与客户端的channel对象不会自动关闭,还在保持这个链接,造成资源浪费。为了解决这些已经失效的长连接,我们怎么处理呢?

客户端定时向服务器端发送心跳包,固定的心跳,固定3分钟、5分钟或者是10分钟来发送心跳,网络情况是比较复杂的,有时候网络情况是好的,有时候网络情况是差的,选择最短的时间。降低用户的流量问题,通过智能心跳的问题,来降低手机的电量的消耗。 

客户端定期向服务器发送心跳,服务器检测连接的读、写空闲时间是否超时。如果连接在持续时间t没有读取、发送任务消息,则认为连接出现异常,将连接进行关闭,释放资源,如图5:

blob.png


Netty提供的空闲检测机制分为三种:

1) 读空闲,链路持续时间t没有读取到任何消息;

2) 写空闲,链路持续时间t没有发送任何消息;

3) 读写空闲,链路持续时间t没有接收或者发送任何消息。

Netty的默认读写空闲机制是发生超时异常,关闭连接,但是,我们可以定制它的超时实现机制,以便支持不同的用户场景


  服务端增加对空闲时间处理pipeline.addLast("ping", new IdleStateHandler(MAX_IDLE_TIME, MAX_IDLE_TIME, MAX_IDLE_TIME)) 然后在业务逻辑的Handler里面,重写 userEventTriggered(ChannelHandlerContext ctx, Object evt),如果获取到IdleState.ALL_IDLE则定时向客户端发送心跳包;客户端在业务逻辑的Handler里面,如果接到心跳包,则向服务器发送一个心跳反馈;服务端如果长时间没有接受到客户端的信息,即IdleState.READER_IDLE被触发,则关闭当前的channel。

调用代码是:

socketChannel.pipeline().addLast("IdleStateHandler",
											new IdleStateHandler( MAX_IDLE_TIME,  MAX_IDLE_TIME,  MAX_IDLE_TIME ));
									socketChannel.pipeline().addLast("IdlChannelHandlerAdapter",
											new IdlChannelHandlerAdapter());
/*****
 * 空闲连接处理逻辑
 * ******/
public class IdlChannelHandlerAdapter extends ChannelHandlerAdapter {



	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
			throws Exception {
		super.userEventTriggered(ctx, evt);
		if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state().equals(IdleState.READER_IDLE)) {
                System.out.println("READER_IDLE");
                // 超时关闭channel
                ctx.disconnect();
                ctx.channel().close();
            } else if (event.state().equals(IdleState.WRITER_IDLE)) {
                System.out.println("WRITER_IDLE");
            } else if (event.state().equals(IdleState.ALL_IDLE)) {
                System.out.println("ALL_IDLE");
                // 发送心跳
//                ctx.channel().write("ping\n");
            }
        }
	}
}





一键分享文章

分类列表

  • • struts源码分析
  • • flink
  • • struts
  • • redis
  • • kafka
  • • ubuntu
  • • zookeeper
  • • hadoop
  • • activiti
  • • linux
  • • 成长
  • • NIO
  • • 关键词提取
  • • mysql
  • • android studio
  • • zabbix
  • • 云计算
  • • mahout
  • • jmeter
  • • hive
  • • ActiveMQ
  • • lucene
  • • MongoDB
  • • netty
  • • flume
  • • 我遇到的问题
  • • GRUB
  • • nginx
  • • 大家好的文章
  • • android
  • • tomcat
  • • Python
  • • luke
  • • android源码编译
  • • 安全
  • • MPAndroidChart
  • • swing
  • • POI
  • • powerdesigner
  • • jquery
  • • html
  • • java
  • • eclipse
  • • shell
  • • jvm
  • • highcharts
  • • 设计模式
  • • 列式数据库
  • • spring cloud
  • • docker+node.js+zookeeper构建微服务
版权所有 cookqq 感谢访问 支持开源 京ICP备15030920号
CopyRight 2015-2018 cookqq.com All Right Reserved.