Netty自带心跳检测功能,IdleStateHandler,客户端在写空闲时主动发起心跳请求,服务器接受到心跳请求后给出一个心跳响应。当客户端在一定时间范围内不能够给出响应则断开链接。

  1. public class NettyClient {
  2. public void connect(String remoteServer, int port) throws Exception {
  3. EventLoopGroup workerGroup = new NioEventLoopGroup();
  4. try {
  5. Bootstrap b = new Bootstrap();
  6. b.group(workerGroup).channel(NioSocketChannel.class).remoteAddress(remoteServer, port)
  7. .handler(new ChildChannelHandler());
  8. ChannelFuture f = b.connect();
  9. System.out.println("Netty time Client connected at port " + port);
  10. f.channel().closeFuture().sync();
  11. } finally {
  12. try {
  13. TimeUnit.SECONDS.sleep(5);
  14. try {
  15. System.out.println("重新链接。。。");
  16. connect(remoteServer, port);
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. }
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }
  25. public static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
  26. @Override
  27. protected void initChannel(final SocketChannel ch) throws Exception {
  28. // -8表示lengthAdjustment,让解码器从0开始截取字节,并且包含消息头
  29. ch.pipeline().addLast(new RpcEncoder(NettyMessage.class)).addLast(new RpcDecoder(NettyMessage.class))
  30. .addLast(new IdleStateHandler(120, 10, 0, TimeUnit.SECONDS)).addLast(new HeartBeatReqHandler());
  31. }
  32. }
  33. public static void main(String[] args) {
  34. try {
  35. new NettyClient().connect("127.0.0.1", 12000);
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  1. public class SerializationUtil {
  2. private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();
  3. private static Objenesis                objenesis    = new ObjenesisStd(true);
  4. private static <T> Schema<T> getSchema(Class<T> clazz) {
  5. @SuppressWarnings("unchecked")
  6. Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
  7. if (schema == null) {
  8. schema = RuntimeSchema.getSchema(clazz);
  9. if (schema != null) {
  10. cachedSchema.put(clazz, schema);
  11. }
  12. }
  13. return schema;
  14. }
  15. /**
  16. * 序列化
  17. *
  18. * @param obj
  19. * @return
  20. */
  21. public static <T> byte[] serializer(T obj) {
  22. @SuppressWarnings("unchecked")
  23. Class<T> clazz = (Class<T>) obj.getClass();
  24. LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
  25. try {
  26. Schema<T> schema = getSchema(clazz);
  27. byte result[] = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
  28. return result;
  29. } catch (Exception e) {
  30. throw new IllegalStateException(e.getMessage(), e);
  31. } finally {
  32. buffer.clear();
  33. }
  34. }
  35. /**
  36. * 反序列化
  37. *
  38. * @param data
  39. * @param clazz
  40. * @return
  41. */
  42. public static <T> T deserializer(byte[] data, Class<T> clazz) {
  43. try {
  44. T obj = objenesis.newInstance(clazz);
  45. Schema<T> schema = getSchema(clazz);
  46. ProtostuffIOUtil.mergeFrom(data, obj, schema);
  47. return obj;
  48. } catch (Exception e) {
  49. throw new IllegalStateException(e.getMessage(), e);
  50. }
  51. }
  52. }
  1. @SuppressWarnings("rawtypes")
  2. public class RpcEncoder extends MessageToByteEncoder {
  3. private Class<?> genericClass;
  4. public RpcEncoder(Class<?> genericClass) {
  5. this.genericClass = genericClass;
  6. }
  7. @Override
  8. public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) throws Exception {
  9. if (genericClass.isInstance(in)) {
  10. System.out.println("发送的请求是:"+in);
  11. byte[] data = SerializationUtil.serializer(in);
  12. out.writeInt(data.length);
  13. out.writeBytes(data);
  14. }
  15. }
  16. }
  1. public class RpcDecoder extends ByteToMessageDecoder {
  2. private Class<?> genericClass;
  3. public RpcDecoder(Class<?> genericClass) {
  4. this.genericClass = genericClass;
  5. }
  6. @Override
  7. public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
  8. throws Exception {
  9. if (in.readableBytes() < 4) {
  10. return;
  11. }
  12. in.markReaderIndex();
  13. int dataLength = in.readInt();
  14. if (dataLength < 0) {
  15. ctx.close();
  16. }
  17. if (in.readableBytes() < dataLength) {
  18. in.resetReaderIndex();
  19. }
  20. byte[] data = new byte[dataLength];
  21. in.readBytes(data);
  22. Object obj = SerializationUtil.deserializer(data, genericClass);
  23. System.out.println("接收到的消息是:"+obj);
  24. out.add(obj);
  25. }
  26. }
  1. public class HeartBeatReqHandler extends ChannelDuplexHandler {
  2. /**
  3. * @see io.netty.channel.ChannelInboundHandlerAdapter#userEventTriggered(io.netty.channel.ChannelHandlerContext,
  4. *      java.lang.Object)
  5. */
  6. @Override
  7. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  8. if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
  9. IdleStateEvent event = (IdleStateEvent) evt;
  10. if (event.state() == IdleState.READER_IDLE) {
  11. System.out.println("read 空闲");
  12. ctx.disconnect();
  13. } else if (event.state() == IdleState.WRITER_IDLE) {
  14. System.out.println("write 空闲");
  15. ctx.writeAndFlush(buildHeartBeat(MessageType.HEARTBEAT_REQ.getType()));
  16. }
  17. }
  18. }
  19. /**
  20. *
  21. * @return
  22. * @author zhangwei<wei.zw@corp.netease.com>
  23. */
  24. private NettyMessage buildHeartBeat(byte type) {
  25. NettyMessage msg = new NettyMessage();
  26. Header header = new Header();
  27. header.setType(type);
  28. msg.setHeader(header);
  29. return msg;
  30. }
  31. }
  1. public class NettyServer {
  2. public void bind(int port) throws Exception {
  3. EventLoopGroup bossGroup = new NioEventLoopGroup();
  4. EventLoopGroup workerGroup = new NioEventLoopGroup();
  5. try {
  6. ServerBootstrap b = new ServerBootstrap();
  7. b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
  8. .childHandler(new ChildChannelHandler());
  9. ChannelFuture f = b.bind(port).sync();
  10. System.out.println("Netty time Server started at port " + port);
  11. f.channel().closeFuture().sync();
  12. } finally {
  13. bossGroup.shutdownGracefully();
  14. workerGroup.shutdownGracefully();
  15. }
  16. }
  17. public static class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
  18. @Override
  19. protected void initChannel(final SocketChannel ch) throws Exception {
  20. ch.pipeline().addLast(new RpcDecoder(NettyMessage.class)).addLast(new RpcEncoder(NettyMessage.class))
  21. .addLast(new IdleStateHandler(120, 0, 0, TimeUnit.SECONDS)).addLast(new HeartBeatRespHandler());
  22. }
  23. }
  24. public static void main(String[] args) {
  25. try {
  26. new NettyServer().bind(12000);
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  1. public enum MessageType {
  2. LOGIN_REQ((byte) 1), LOGIN_RESP((byte) 2), HEARTBEAT_REQ((byte) 3), HEARTBEAT_RESP((byte) 4);
  3. private byte type;
  4. /**
  5. * @param type
  6. */
  7. private MessageType(byte type) {
  8. this.type = type;
  9. }
  10. public byte getType() {
  11. return type;
  12. }
  13. public void setType(byte type) {
  14. this.type = type;
  15. }
  16. public static MessageType getMessageType(byte type) {
  17. for (MessageType b : MessageType.values()) {
  18. if (b.getType() == type) {
  19. return b;
  20. }
  21. }
  22. return null;
  23. }
  24. }
  1. public class HeartBeatRespHandler extends SimpleChannelInboundHandler<NettyMessage> {
  2. /**
  3. * @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext,
  4. *      java.lang.Object)
  5. */
  6. @Override
  7. protected void channelRead0(ChannelHandlerContext ctx, NettyMessage msg) throws Exception {
  8. if (msg.getHeader() != null && msg.getHeader().getType() == MessageType.HEARTBEAT_REQ.getType()) {
  9. NettyMessage heartBeat = buildHeartBeat(MessageType.HEARTBEAT_RESP.getType());
  10. ctx.writeAndFlush(heartBeat);
  11. } else {
  12. ctx.fireChannelRead(msg);
  13. }
  14. }
  15. /**
  16. * @see io.netty.channel.ChannelInboundHandlerAdapter#userEventTriggered(io.netty.channel.ChannelHandlerContext,
  17. *      java.lang.Object)
  18. */
  19. @Override
  20. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  21. if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
  22. IdleStateEvent event = (IdleStateEvent) evt;
  23. if (event.state() == IdleState.READER_IDLE) {
  24. System.out.println("read 空闲 关闭链接");
  25. ctx.disconnect();
  26. }
  27. }
  28. }
  29. /**
  30. *
  31. * @return
  32. * @author zhangwei<wei.zw@corp.netease.com>
  33. */
  34. private NettyMessage buildHeartBeat(byte type) {
  35. NettyMessage msg = new NettyMessage();
  36. Header header = new Header();
  37. header.setType(type);
  38. msg.setHeader(header);
  39. return msg;
  40. }
  41. }
  1. public class NettyMessage implements Serializable{
  2. /**  */
  3. private static final long serialVersionUID = 1L;
  4. private Header header;
  5. private Object body;
  6. public Header getHeader() {
  7. return header;
  8. }
  9. public void setHeader(Header header) {
  10. this.header = header;
  11. }
  12. public Object getBody() {
  13. return body;
  14. }
  15. public void setBody(Object body) {
  16. this.body = body;
  17. }
  18. /**
  19. * @see java.lang.Object#toString()
  20. */
  21. @Override
  22. public String toString() {
  23. return "NettyMessage [header=" + header + ", body=" + body + "]";
  24. }
  25. }
  1. public class Header implements Serializable{
  2. /**  */
  3. private static final long serialVersionUID = 1L;
  4. private int crcCode=0xabef0101;
  5. private int length;
  6. private long sessionId;
  7. private byte type;
  8. private byte priority;
  9. private Map<String,Object> attachment=new HashMap<>();
  10. public int getCrcCode() {
  11. return crcCode;
  12. }
  13. public void setCrcCode(int crcCode) {
  14. this.crcCode = crcCode;
  15. }
  16. public int getLength() {
  17. return length;
  18. }
  19. public void setLength(int length) {
  20. this.length = length;
  21. }
  22. public long getSessionId() {
  23. return sessionId;
  24. }
  25. public void setSessionId(long sessionId) {
  26. this.sessionId = sessionId;
  27. }
  28. public byte getType() {
  29. return type;
  30. }
  31. public void setType(byte type) {
  32. this.type = type;
  33. }
  34. public byte getPriority() {
  35. return priority;
  36. }
  37. public void setPriority(byte priority) {
  38. this.priority = priority;
  39. }
  40. public Map<String, Object> getAttachment() {
  41. return attachment;
  42. }
  43. public void setAttachment(Map<String, Object> attachment) {
  44. this.attachment = attachment;
  45. }
  46. /**
  47. * @see java.lang.Object#toString()
  48. */
  49. @Override
  50. public String toString() {
  51. return "Header [crcCode=" + crcCode + ", length=" + length + ", sessionId=" + sessionId + ", type=" + type
  52. + ", priority=" + priority + ", attachment=" + attachment + "]";
  53. }
  54. }

客户端的结果是:

  1. etty time Client connected at port 12000
  2. write 空闲
  3. 发送的请求是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=3, priority=0, attachment={}], body=null]
  4. 接收到的消息是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=4, priority=0, attachment={}], body=null]
  5. write 空闲
  6. 发送的请求是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=3, priority=0, attachment={}], body=null]
  7. 接收到的消息是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=4, priority=0, attachment={}], body=null]
  8. write 空闲
  9. 发送的请求是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=3, priority=0, attachment={}], body=null]
  10. 接收到的消息是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=4, priority=0, attachment={}], body=null]
  11. write 空闲
  12. 发送的请求是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=3, priority=0, attachment={}], body=null]
  13. 接收到的消息是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=4, priority=0, attachment={}], body=null]
  14. write 空闲
  15. 发送的请求是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=3, priority=0, attachment={}], body=null]
  16. 接收到的消息是:NettyMessage [header=Header [crcCode=-1410399999, length=0, sessionId=0, type=4, priority=0, attachment={}], body=null]

Netty通过心跳保持长链接的更多相关文章

  1. netty长链接保存方案

    架构 client router server zk redis 对于router: 保存客户端和服务器对 redis clientid : serverip & port 对于server ...

  2. Netty学习(八)-Netty的心跳机制

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a953713428/article/details/69378412我们知道在TCP长连接或者Web ...

  3. 【Netty】利用Netty实现心跳检测和重连机制

    一.前言 心跳机制是定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性的机制.   我们用到的很多框架都用到了心跳检测,比如服务注册到 Eureka Server 之后会维 ...

  4. 纯Socket(BIO)长链接编程的常见的坑和填坑套路

    本文章纯属个人经验总结,伪代码也是写文章的时候顺便白板编码的,可能有逻辑问题,请帮忙指正,谢谢. Internet(全球互联网)是无数台机器基于TCP/IP协议族相互通信产生的.TCP/IP协议族分了 ...

  5. Netty之心跳检测技术(四)

    Netty之心跳检测技术(四) 一.简介 "心跳"听起来感觉很牛X的样子,其实只是一种检测端到端连接状态的技术.举个简单的"栗子",现有A.B两端已经互相连接, ...

  6. Netty实现心跳机制

    netty心跳机制示例,使用Netty实现心跳机制,使用netty4,IdleStateHandler 实现.Netty心跳机制,netty心跳检测,netty,心跳 本文假设你已经了解了Netty的 ...

  7. python+uwsgi导致redis无法长链接引起性能下降问题记录

    今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...

  8. PHP实现新浪长链接转化成短链接API

    我们经常收到类似于这样的短信(如下图),发现其中的链接并不是常规的网址链接,而是个短小精悍的短链接,产品中经常需要这样的需求,如果在给用户下发的短信中是一个很长的连接,用户体验肯定很差,因此我们需要实 ...

  9. 长链接转换成短链接(iOS版本)

    首先需要将字符串使用md5加密,添加NSString的md5的类别方法如下 .h文件 #import <CommonCrypto/CommonDigest.h> @interface NS ...

随机推荐

  1. HDU5726 GCD

    Give you a sequence of N(N≤100,000)N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000)a1,...,an( ...

  2. Redis主从复制简单介绍

    由于本地环境的使用,所以搭建一个本地的Redis集群,本篇讲解Redis主从复制集群的搭建,使用的平台是Windows,搭建的思路和Linux上基本一致! (精读阅读本篇可能花费您15分钟,略读需5分 ...

  3. IntelliJ IDEA 使用技巧一览表

    IntelliJ IDEA使用技巧一览表 在使用 InelliJ IDEA 的过程中,通过查找资料以及一些自己的摸索,发现这个众多 Java 程序员喜欢的 IDE 里有许多值得一提的小窍门,如果能熟练 ...

  4. Docker分层原理与内部结构

    转自:1 :   https://www.csdn.net/article/2015-08-21/2825511 2:    http://blog.51cto.com/wzlinux/2044797 ...

  5. 恶补一下DP+背包专题(刷刷水题)L2

    开心的金明 题目大意 就是求一定背包容量的最大值 思路 想必大家都知道,一看到这种题目,就会想起01背包 虽然特别简单但是还是讲一下吧 状态设置 由于这题差不多是一个01背包的版子题,那么我们就只需要 ...

  6. 浏览器的 16ms 渲染帧

    标签 归档 关于arttle Land 浏览器的 16ms 渲染帧 DOM JavaScript 异步 性能 重绘 由于现在广泛使用的屏幕都有固定的刷新率(比如最新的一般在 60Hz), 在两次硬件刷 ...

  7. mdf 与 mdb的对比

    下面的内容从网上搜索而来,未经过本人严格验证,仅供参考. 1.问:mdb数据库能否脱离Access运行?即,没有安装Access,可以打开mdb吗? 答:可以,脱离Access运行,可以到微软的同类产 ...

  8. android的布局-----GridLayout(网格布局)

    学习导图 (一)简介 网格布局由GridLayout所代表,在android4.0之后新增加的布局管理器,因此需要android4.0之后的版本中使用,如果在更早的平台使用该布局管理器,则需要导入相应 ...

  9. UnionFind(PYthon实现)

    UnionFind用于解决图的连通性问题,不需要给出具体路径的情况,可用来计算连通分支数 参考链接: https://blog.csdn.net/dm_vincent/article/details/ ...

  10. 涂色问题(Python)

    题目:将一个圆形等分成N个小扇形,将这些扇形标记为1,2,3,-,N.现在使用M种颜色对每个扇形进行涂色,每个扇形涂一种颜色,且相邻的扇形颜色不同,问有多少种不同的涂法?(N≥1,M≥3) 参考:ht ...