如何阅读源码
一段一段看
- 断点
- 打印日志
- 看调用栈
- 搜索
心跳
心跳其实就是一个普通的请求,特点数据简单,业务也简单。
心跳对于服务端来说,定时清除闲置会话inactive(netty5) channelclose(netty3)
心跳对客户端来说,用来检测会话是否断开,是否重连! 用来检测网络延时!
心跳具体实现
基于 netty3
server
server 当检测到时 client 心跳包时,根据自定义心跳协议,回传给 Client 信息。
-
学习idleStateHandler
用来检测会话状态
需要用到 SimpleChannelHandlerSimpleChannelHandler
idleStateAwareChannelHandler
HelloHandler extends idleStateAwareChannelHandler implements ChannelHandler
HelloHandler extends SimpleChannelHandler
@Override
public void handleUpstream(final ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof IdleStateEvent) {
if(((IdleStateEvent)e).getState() == IdleState.ALL_IDLE){
System.out.println("提玩家下线");
//关闭会话,踢玩家下线
ChannelFuture write = ctx.getChannel().write("time out, you will close");
write.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.getChannel().close();
}
});
}
} else {
super.handleUpstream(ctx, e);
}
}
- 设置超时状态
读超时:
写超时:
读写超时:
如果有 client 有读写操作,将重置此时间。 - 超时时的业务处理选择
- 如果超时 server 清除此 channel
- 发消息给此 channel
- channel.close
到此 client 显示将丢失连接
Client
自定义消息,定时发送 心跳包,传递基本信息。
if channelDisconnected channelClosed
重连
状态:
SimpleChannelHandler
下面只是简要代码
package com.heart.client;
import com.heart.MyDate;
import org.jboss.netty.channel.*;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author: Jie
* @Date: 2019/3/18 16:19
* @Function :
*/
public class ClientHandler extends SimpleChannelHandler {
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
super.messageReceived(ctx, e);
System.out.println("客户端 接收到消息:"+e.getMessage());
}
@Override
public void handleUpstream(final ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
if (e instanceof IdleStateEvent) {
String time =MyDate.getNowDate();
if(((IdleStateEvent)e).getState()== IdleState.READER_IDLE){
System.out.println(time+ " read Idle " );
}else if(((IdleStateEvent)e).getState()== IdleState.WRITER_IDLE){
System.out.println(time + " write Idle");
}else if(((IdleStateEvent)e).getState() == IdleState.ALL_IDLE){
System.out.println(time+"提玩家下线");
//关闭会话,踢玩家下线
ChannelFuture write = ctx.getChannel().write("time out, you will close");
write.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
ctx.getChannel().close();
}
});
}
} else {
super.handleUpstream(ctx, e);
}
}
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelConnected(ctx, e);
System.out.println("channelConnected");
}
//只有当本地客户机已经成功的与远程主机建立连接(connected)时,连接断开的时候才会触发channelDisconnected事件
@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("channelDisconnected");
}
@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelClosed(ctx, e);
System.out.println("channelClosed");
}
}
tryReconnect 没贴出,需要注意的点:
- 注意包大小
只应包含基本的必要信息。 - 判断网络
receiver接收当前网络变化,
当网络可用时重连 - 看当前业务是否需要重连
eg. 机器升级中,不需要重连推迟重连。
登录中,不需要重连。 - close 当前连接
- 防止多次重连造成并发与开销
- Pipeline中 keepAlive、tcpNoDelay true
备注: 之前采用netty(3.6.6-fianl)支持通道检测IdleStateHandler,发现有些机型
手机休眠之后IdleStateHandler 定时器HashedWheelTimer可能存在被系统停止关闭的现象
所以采用AlarmManager 进行心跳的检测
登陆之后就开始触发心跳检测 【仅仅是在线,重练就会取消的】
退出reset 会释放alarmManager 资源