# netty-server-client **Repository Path**: dengfeng/netty-server-client ## Basic Information - **Project Name**: netty-server-client - **Description**: 完成服务端与客户端的长连接通信,基于netty4,实现了心跳监测和自动重连,实现了spring-boot-starter,引入即可使用。 - **Primary Language**: Java - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-05-07 - **Last Updated**: 2023-06-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### Server- Client 长连接组件 **Springboot2**集成 **netty4** ,使用protobuf作为数据封包,实现了服务端与多客户端的长连接,封装了自动登录、token验证、数据发送接收、心跳监测、断线重连等功能,并实现了spring-boot-starter,项目中引入即可使用。 ### 开发环境 - JDK 8+ - springboot 2.4.13 - Netty 4+ - protobuf-java 3.3.0 ### 已完成功能 - 客户端授权验证 - 数据包token校验 - 心跳检测 - 断线重连、断线通知 - 异步方式发送/接收消息 - 同步方式发送消息并获取返回结果 ### 心跳实现详细过程 1. 客户端网络空闲10秒(默认)没有进行读写操作,进行发送一次ping心跳给服务端; 2. 客户端如果在下一个发送ping心跳周期来临时,还没有收到服务端pong的心跳应答,则失败心跳计数器加1,如果连续超过2次没有收到服务端的心跳回复,则断开当前连接,以5秒的间隔进行重连操作,直到重连成功; 3. 服务端网络空闲状态到达15秒(默认)后,服务端没有收到客户端的ping消息,将关闭链路,释放资源,等待客户端重连; ### 使用方法 **服务端** 1.引入netty server ``` com.heyi netty-heart-server-starter 1.2.0 ``` 2.配置参数(无必配项,可不配置使用默认参数),在application.properties里设置 ``` # 设置服务器IP和端口,不设置默认为0.0.0.0:10018 netty.server.host=127.0.0.1 netty.server.port=10018 # 修改netty性能设置,可不设置使用默认值(1, 4) netty.server.bossCount=1 netty.server.workerCount=10 # 心跳间隔时间 不设置默认10秒 netty.server.heartSeconds = 10; # 如果想不启动netty,设置 netty.server.enabled=false ``` 3.接收客户端数据,实现ChannelDataListener接口 ``` @Component public class ServerNettyListener implements ChannelDataListener { @Autowired ClientService clientService; @Override public boolean authority(String clientId, long timestamp, String sing) { // 验证规则 sign=md5(client+timestamp+clientSecret) if(clientService.valid(clientId, sing)){ // 有需要的话,可进一步验证timestamp,如timestamp只允许提交一次,timestamp只在10秒内有效 log.info("新增一个客户端:"+clientId); return true; } return false; } @Override public void receiveData(MessageHandler messageHandler) { log.info("接收到客户端"+messageHandler.getMessage().getClientId() + "的消息:"+ messageHandler.getMessage().getData()); // 如果客户端使用同步sendMessageAndReturn发送消息,则第一条消息为回复消息,后面的消息为新消息 messageHandler.sendMessage("回复消息"); } @Override public void disconnected(String clientId, Throwable cause) { log.info("客户端"+clientId + "断开连接:"+ cause.getMessage()); } } ``` 4.向客户端发送消息 41. 异步方式(推荐) ``` // 注入NettyServer对象 @Autowired NettyServer nettyServer; // 使用sendMessage方法, 有返回消息的话在ChannelDataListener中处理 nettyServer.sendMessage(clientId, "测试消息"); // 还可以监听发送成功消息 nettyServer.sendMessage(clientId, "测试消息").addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if(channelFuture.isSuccess()){ log.info("消息发送成功:"+json); } } }); ``` 42. 同步方式(此方式会阻塞线程,非必要不推荐使用) ``` // 注入NettyServer对象 @Autowired NettyServer nettyServer; // 向客户端[clientId]发送消息并获得客户端返回内容,若 10秒后客户端无返回则报超时错误 String msg = nettyServer.sendMessageAndReturn(clientId, "测试消息", 10); !注意:sendMessageAndReturn方法需要客户端的ChannelDataListener中使用 messageHandler.sendMessage("回复消息") 语句回复消息(若有多条,则第一条为回复消息),而不能用 nettyClient.sendMessage(msg) ``` **客户端** 1.引入netty client ``` com.heyi netty-heart-client-starter 1.2.0 ``` 2.配置参数,在application.properties里设置 ``` # 设置客户端id和密钥 netty.clientId=test netty.clientSecret=123456 # 设置服务器的IP和端口 netty.serverHost=127.0.0.1 netty.serverPort=10018 # 心跳间隔时间 不设置默认10秒 netty.heartSeconds = 10; # 如果想不启动netty client,设置 netty.client.enabled=false ``` 3.数据处理,实现ChannelDataListener接口 ``` @Component public class NettyClientListener implements ChannelDataListener { @Override public void authority(boolean auth) { if(auth) { log.info("连接服务端验证通过"); }else { log.info("连接服务端验证没通过"); } } @Override public void receiveData(MessageHandler messageHandler) { log.info("收到数据:" + messageHandler.getMessage().getData()); // 如果有需要,可以回复消息 messageHandler.sendMessage("回复消息"); } @Override public void disconnected() { log.info("连接已断开"); } } ``` 4.向服务端发送消息 41. 异步方式(推荐) ``` // 注入NettyClient对象 @Autowired private NettyClient nettyClient; // 使用sendMessage方法, 有返回消息的话在ChannelDataListener中处理 nettyClient.sendMessage(msg); // 还可以监听发送成功消息 nettyClient.sendMessage("测试消息").addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if(channelFuture.isSuccess()){ log.info("消息发送成功:"+json); } } }); ``` 42. 同步方式(此方式会阻塞线程,非必要不推荐使用) ``` // 注入NettyServer对象 @Autowired NettyClient nettyClient; // 向服务端发送消息并获得服务端返回内容,若 10秒后服务端无返回则报超时错误 String msg = nettyClient.sendMessageAndReturn("测试消息", 10); !注意:sendMessageAndReturn方法需要服务端的ChannelDataListener中使用 messageHandler.sendMessage("回复消息") 语句回复消息,而不能用 nettyServer.sendMessage(msg) ``` ### 版本记录 >**- 1.2.0** >>- 已登录的clientId,其它终端无法重复登录 >>- 已登录验证的数据发送使用token,防止绕开验证直接发送数据 >>- 增加服务端和客户端同步发送消息方法,同步阻塞等待客户端返回消息 >**- 1.1.0** >>- 将默认心跳从1分钟改为10秒(断线重连时间缩短到20S) >>- 允许通过配置改变心跳间隔 >>- 登录验证没通过后,尝试3次后不再继续登录 >>- 已登录的clientId重复登录,前一个会释放资源并清除 >**- 1.0.0** >>- 客户端授权验证 >>- 心跳检测 >>- 断线重连、断线通知 >>- 异步方式发送/接收消息