項目背景:
硬件設備和服務器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);
}
}