项目背景:
硬件设备和服务器websocket长连接通讯
使用技术:
java/netty
心跳频率和关闭时长:
看设备接入数和业务要求,比如6秒一个心跳包,对方收到后也返回一个心跳响应。双方2.5个周期内没收到数据则关闭各自链接。常用心跳周期如2s,4s,6s,8s,10s...
哪个来发:
根据我们业务,服务器端来主动发心跳包。开始心跳周期可以设置长点,比如10s。如果业务需求心跳检查要迅速,则修改服务器端的心跳周期,设备固件升级。对于未升级的设备在一个关闭时长内可能会收到2个以上心跳包,不受影响。
代码实现:
READ_IDEL_TIME_OUT=25s
WRITE_IDEL_TIME_OUT=15s
ALL_IDEL_TIME_OUT=10s
HEARTBEAT_REQUEST=“H”
HEARTBEAT_RESPONSE=“B”
inboundHandler继承的是SimpleChannelInboundHandler<TextWebSocketFrame> 类。
服务器端:
step1. pipeline初始化配置
pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
step2. 在任何一个handler里实现userEventTriggered方法
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state().equals(IdleState.READER_IDLE)) {
//未进行读操作
log.error("READER_IDLE");
// 超时关闭channel
ctx.close();
} else if (event.state().equals(IdleState.WRITER_IDLE)) {
//log.error("WRITER_IDLE");
} else if (event.state().equals(IdleState.ALL_IDLE)) {
//未进行读写
log.info("SEND HeartBeat:H");
ctx.channel().writeAndFlush(new TextWebSocketFrame(HEARTBEAT_REQUEST));
}
}
}
服务器端:
step1. pipeline初始化配置
pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
step2. 在任何一个handler里实现userEventTriggered方法
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state().equals(IdleState.READER_IDLE)) {
//未进行读操作
log.error("READER_IDLE");
// 超时关闭channel
ctx.close();
} else if (event.state().equals(IdleState.WRITER_IDLE)) {
//log.error("WRITER_IDLE");
} else if (event.state().equals(IdleState.ALL_IDLE)) {
//未进行读写
}
}
}
step3.收到服务器心跳后,响应
@Override
protected void channelRead0(ChannelHandlerContext arg0, TextWebSocketFrame arg1) throws Exception {
// TODO Auto-generated method stub
String txt=arg1.text();
log.info("RECV:"+arg1.text());
if (HEARTBEAT_REQUEST.equals(txt)){
arg0.channel().writeAndFlush(new TextWebSocketFrame(HEARTBEAT_RESPONSE) ).sync();
log.info("SEND:"+HEARTBEAT_RESPONSE);
}
}