netty(十三)tcp心跳实践
理论模型:https://www.cnblogs.com/silyvin/p/9605033.html
本次作实践,序列号承接 netty(十一)protobuf
客户端:
pipeline.addLast(new IdleStateHandler(61, 30, 0, TimeUnit.SECONDS));
pipeline.addLast(new ClientHeartbeatHandler());
//处理类
pipeline.addLast(new ClientHandler4Heart());
需要Read和Write idle都设置,因为我们的心跳是由客户端主动发送的
public class ClientHeartbeatHandler extends ChannelInboundHandlerAdapter {
@Override
public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
if(evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if(event.state() == IdleState.WRITER_IDLE) {
System.out.println("* CLIENT WRITER_IDLE send msg heart_beat...");
sendHeartbeat(ctx);
} else if (event.state() == IdleState.READER_IDLE) {
System.out.println("* CLIENT has not receive SERVER msg, so CLOSE\n");
ctx.close();
}
}
}
private void sendHeartbeat(final ChannelHandlerContext ctx) {
MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder();
builder.setCode(0);
builder.setMsg("Heartbeat");
ctx.channel().writeAndFlush(builder.build());
}
}
30s主动发送一次心跳,61s未收到任何消息(含心跳-&-普通消息)即close连接
public class ClientHandler4Heart extends SimpleChannelInboundHandler<MyBaseProto.BaseProto> {
//接受服务端发来的消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyBaseProto.BaseProto msg) throws Exception {
if("Heartbeat".equals(msg.getMsg())) {
System.out.println("* CLIENT receive back heart");
} else {
System.out.println("SERVER'S general msg RESPONSE : "+ msg.toString());
}
}
//与服务器建立连接
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
//给服务器发消息
MyBaseProto.BaseProto.Builder builder = MyBaseProto.BaseProto.newBuilder();
builder.setCode(1);
builder.setMsg("hello");
ctx.channel().writeAndFlush(builder.build());
}
active后随即发送一条普通消息,read函数中,对心跳与普通消息分别处理
服务端:
pipeline.addLast(new IdleStateHandler(61, 0, 0, TimeUnit.SECONDS));
pipeline.addLast(new ServerHeartbeatHandler());
//处理类
pipeline.addLast(new ServerHandler4V2Heart());
服务端仅需要ReadIdle
public class ServerHeartbeatHandler extends ChannelInboundHandlerAdapter {
@Override
public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
if(evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.READER_IDLE) {
System.out.println("* SERVER has not receive CLIENT msg, so CLOSE\n");
ctx.close();
}
}
}
}
61s,即连续2个30s未收到任何消息(普通消息&心跳)后(1s作冗余时间储备),close连接
public class ServerHandler4V2Heart extends SimpleChannelInboundHandler<MyBaseProtoV2.BaseProto> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyBaseProtoV2.BaseProto msg) throws Exception {
if("Heartbeat".equals(msg.getMsg())) {
System.out.println("* SERVER receive heart and send back");
writeAndFlush(ctx, msg);
} else {
System.out.println("general msg, send RESPONSE --------\n"+msg.toString());
MyBaseProtoV2.BaseProto.Builder builder = MyBaseProtoV2.BaseProto.newBuilder();
builder.setCode(msg.getCode() + 1);
builder.setMsg("SERVER:" + msg.getMsg());
writeAndFlush(ctx, builder.build());
}
}
对心跳和普通消息分别处理
运行2分钟:
客户端:
SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT receive back heart
服务端:
server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"
* SERVER receive heart and send back
* SERVER receive heart and send back
* SERVER receive heart and send back
干掉服务端的返回心跳,以模拟一段时间后断网断电情况:
public class ServerHandler4V2Heart extends SimpleChannelInboundHandler<MyBaseProtoV2.BaseProto> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyBaseProtoV2.BaseProto msg) throws Exception {
if("Heartbeat".equals(msg.getMsg())) {
// System.out.println("* SERVER receive heart and send back");
// writeAndFlush(ctx, msg);
客户端:
SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT WRITER_IDLE send msg heart_beat...
* CLIENT has not receive SERVER msg, so CLOSE
channelInactive
服务端:
server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"
channelInactive
2次未收到心跳回复1s后,client close channel
干掉客户端的发送心跳,模拟断网断电:
// pipeline.addLast(new IdleStateHandler(61, 30, 0, TimeUnit.SECONDS));
pipeline.addLast(new ClientHeartbeatHandler());
//处理类
pipeline.addLast(new ClientHandler4Heart());
客户端:
SERVER'S general msg RESPONSE : code: 2
msg: "SERVER:hello"
channelInactive
服务端:
server start ......
channelActive
general msg, send RESPONSE --------
code: 1
msg: "hello"
* SERVER has not receive CLIENT msg, so CLOSE
channelInactive
61s未收到任何消息后,server close channel
浙公网安备 33010602011771号