Netty实现消息推送以及内部心跳机制
来源:互联网 发布:csgo优化 编辑:程序博客网 时间:2024/06/05 19:16
Netty实现消息推送以及内部心跳机制
通讯信息的基类,需要实现序列化,定义了信息的类型和客户端ID,方便进行管理
public abstract class BaseMsg implements Serializable{ private static final long serialVersionUID = 1L; private MsgType msgType; private String clientID; public BaseMsg() {this.clientID = Constants.getClientID();} public MsgType getMsgType() {return msgType;}public void setMsgType(MsgType msgType) {this.msgType = msgType;}public String getClientID() {return clientID;}public void setClientID(String clientID) {this.clientID = clientID;}}
请求参数
public class AskParams implements Serializable { private static final long serialVersionUID = 1L; private String auth; public String getAuth() { return auth; } public void setAuth(String auth) { this.auth = auth; }}
常量类,存放客户端ID
public class Constants {private static String clientID;public static String getClientID() {return clientID;}public static void setClientID(String clientID) {Constants.clientID = clientID;}}
客户端登录信息,有用户名和密码
public class LoginMsg extends BaseMsg{String username;String password;public LoginMsg() {super();setMsgType(MsgType.LOGIN);}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}}
枚举类,主要包含消息协议类型的定义
public enum MsgType { PING,ASK,REPLY,LOGIN;}
管理客户端的Channel,封装在map中,便于管理,可以进行添加,移除和获取
public class NettyChannelMap {private static Map<String, SocketChannel> map = new ConcurrentHashMap<String, SocketChannel>(); public static void add(String clientId,SocketChannel socketChannel){ map.put(clientId,socketChannel); } public static Channel get(String clientId){ return map.get(clientId); } public static void remove(SocketChannel socketChannel){ for (Map.Entry entry:map.entrySet()){ if (entry.getValue()==socketChannel){ map.remove(entry.getKey()); } } }}
心跳包传输数据类型
public class PingMsg extends BaseMsg{public PingMsg() {super();setMsgType(MsgType.PING);}}
消息回应类
public class ReplyMsg extends BaseMsg { public ReplyMsg() { super(); setMsgType(MsgType.REPLY); } private ReplyBody body; public ReplyBody getBody() { return body; } public void setBody(ReplyBody body) { this.body = body; }}
实现序列化的信息主体
public class ReplyBody implements Serializable { private static final long serialVersionUID = 1L;}
客户端回应消息
public class ReplyClientBody extends ReplyBody { private String clientInfo; public ReplyClientBody(String clientInfo) { this.clientInfo = clientInfo; } public String getClientInfo() { return clientInfo; } public void setClientInfo(String clientInfo) { this.clientInfo = clientInfo; }}
服务端回应消息
public class ReplyServerBody extends ReplyBody{ private String serverInfo; public ReplyServerBody(String serverInfo) { this.serverInfo = serverInfo; } public String getServerInfo() { return serverInfo; } public void setServerInfo(String serverInfo) { this.serverInfo = serverInfo; }}
客户端的处理类,主要是对于消息类型的判断处理和心跳处理机制的实现
public class NettyClientHandler extends SimpleChannelInboundHandler<BaseMsg>{ @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent e = (IdleStateEvent) evt; switch (e.state()) { case WRITER_IDLE: PingMsg pingMsg=new PingMsg(); ctx.writeAndFlush(pingMsg); System.out.println("send ping to server----------"); break; default: break; } } } protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception { MsgType msgType=baseMsg.getMsgType(); switch (msgType){ case LOGIN:{ //向服务器发起登录 LoginMsg loginMsg=new LoginMsg(); loginMsg.setPassword("yao"); loginMsg.setUsername("robin"); channelHandlerContext.writeAndFlush(loginMsg); }break; case PING:{ System.out.println("receive ping from server----------"); }break; case ASK:{ ReplyClientBody replyClientBody=new ReplyClientBody("client info **** !!!"); ReplyMsg replyMsg=new ReplyMsg(); replyMsg.setBody(replyClientBody); channelHandlerContext.writeAndFlush(replyMsg); }break; case REPLY:{ ReplyMsg replyMsg=(ReplyMsg)baseMsg; ReplyServerBody replyServerBody=(ReplyServerBody)replyMsg.getBody(); System.out.println("receive client msg: "+replyServerBody.getServerInfo()); } default:break; } ReferenceCountUtil.release(msgType); }protected void channelRead0(ChannelHandlerContext arg0, BaseMsg arg1) throws Exception {}}
服务端处理类,消息类型处理以及对于断开连接的客户端的移除
public class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg>{ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { //channel失效,从Map中移除 NettyChannelMap.remove((SocketChannel)ctx.channel()); } protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception { if(MsgType.LOGIN.equals(baseMsg.getMsgType())){ LoginMsg loginMsg=(LoginMsg)baseMsg; if("robin".equals(loginMsg.getUsername())&&"yao".equals(loginMsg.getPassword())){ //登录成功,把channel存到服务端的map中 NettyChannelMap.add(loginMsg.getClientID(),(SocketChannel)channelHandlerContext.channel()); System.out.println("client"+loginMsg.getClientID()+" 登录成功"); } }else{ if(NettyChannelMap.get(baseMsg.getClientID())==null){ //说明未登录,或者连接断了,服务器向客户端发起登录请求,让客户端重新登录 LoginMsg loginMsg=new LoginMsg(); channelHandlerContext.channel().writeAndFlush(loginMsg); } } switch (baseMsg.getMsgType()){ case PING:{ PingMsg pingMsg=(PingMsg)baseMsg; PingMsg replyPing=new PingMsg(); NettyChannelMap.get(pingMsg.getClientID()).writeAndFlush(replyPing); }break; case ASK:{ //收到客户端的请求 AskMsg askMsg=(AskMsg)baseMsg; if("authToken".equals(askMsg.getParams().getAuth())){ ReplyServerBody replyBody=new ReplyServerBody("server info $$$$ !!!"); ReplyMsg replyMsg=new ReplyMsg(); replyMsg.setBody(replyBody); NettyChannelMap.get(askMsg.getClientID()).writeAndFlush(replyMsg); } }break; case REPLY:{ //收到客户端回复 ReplyMsg replyMsg=(ReplyMsg)baseMsg; ReplyClientBody clientBody=(ReplyClientBody)replyMsg.getBody(); System.out.println("receive client msg: "+clientBody.getClientInfo()); }break; default:break; } ReferenceCountUtil.release(baseMsg); }protected void channelRead0(ChannelHandlerContext arg0, BaseMsg arg1) throws Exception {}}
客户端启动类
public class NettyClientBootstrap { private int port; private String host; private SocketChannel socketChannel; private static final EventExecutorGroup group = new DefaultEventExecutorGroup(20); public NettyClientBootstrap(int port, String host) throws InterruptedException { this.port = port; this.host = host; start(); } private void start() throws InterruptedException { EventLoopGroup eventLoopGroup=new NioEventLoopGroup(); Bootstrap bootstrap=new Bootstrap(); bootstrap.channel(NioSocketChannel.class); bootstrap.option(ChannelOption.SO_KEEPALIVE,true); bootstrap.group(eventLoopGroup); bootstrap.remoteAddress(host,port); bootstrap.handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new IdleStateHandler(10,5,0)); socketChannel.pipeline().addLast(new ObjectEncoder()); socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); socketChannel.pipeline().addLast(new NettyClientHandler()); } }); ChannelFuture future =bootstrap.connect(host,port).sync(); if (future.isSuccess()) { socketChannel = (SocketChannel)future.channel(); System.out.println("connect server 成功---------"); } } public static void main(String[]args) throws InterruptedException { Constants.setClientID("001"); NettyClientBootstrap bootstrap=new NettyClientBootstrap(9999,"localhost"); LoginMsg loginMsg=new LoginMsg(); loginMsg.setPassword("yao"); loginMsg.setUsername("robin"); bootstrap.socketChannel.writeAndFlush(loginMsg); while (true){ TimeUnit.SECONDS.sleep(3); AskMsg askMsg=new AskMsg(); AskParams askParams=new AskParams(); askParams.setAuth("authToken"); askMsg.setParams(askParams); bootstrap.socketChannel.writeAndFlush(askMsg); } }}
服务端启动类
public class NettyServerBootstrap { private int port; private SocketChannel socketChannel; public NettyServerBootstrap(int port) throws InterruptedException { this.port = port; bind(); } private void bind() throws InterruptedException { EventLoopGroup boss=new NioEventLoopGroup(); EventLoopGroup worker=new NioEventLoopGroup(); ServerBootstrap bootstrap=new ServerBootstrap(); bootstrap.group(boss,worker); bootstrap.channel(NioServerSocketChannel.class); bootstrap.option(ChannelOption.SO_BACKLOG, 128); //通过NoDelay禁用Nagle,使消息立即发出去,不用等待到一定的数据量才发出去 bootstrap.option(ChannelOption.TCP_NODELAY, true); //保持长连接状态 bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline p = socketChannel.pipeline(); p.addLast(new ObjectEncoder()); p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null))); p.addLast(new NettyServerHandler()); } }); ChannelFuture f= bootstrap.bind(port).sync(); if(f.isSuccess()){ System.out.println("server start---------------"); } } public static void main(String []args) throws InterruptedException { NettyServerBootstrap bootstrap=new NettyServerBootstrap(9999); while (true){ SocketChannel channel=(SocketChannel)NettyChannelMap.get("001"); if(channel!=null){ AskMsg askMsg=new AskMsg(); channel.writeAndFlush(askMsg); } TimeUnit.SECONDS.sleep(5); } }}
阅读全文
0 0
- Netty实现消息推送以及内部心跳机制
- Netty实现消息推送以及内部心跳机制
- Netty维持长连接 消息推送及心跳机制
- Netty 超时机制及心跳程序实现
- Netty 超时机制及心跳程序实现
- 使用Websocket实现消息推送(心跳)
- Netty心跳机制
- 浅析 Netty心跳机制
- netty自定义心跳机制
- Netty-SocketIO实现服务器消息推送
- Netty websocket 实现服务端推送消息
- 浅析 Netty 实现心跳机制与断线重连
- 浅析Netty实现心跳机制与断线重连
- iPhone消息推送机制实现
- ios消息推送机制实现
- iPhone消息推送机制实现
- iPhone消息推送机制实现
- 如何实现消息推送机制
- 端口号的分类
- gdb调试多好几次&线程
- 狼tuzi
- 算法优化策略
- 50个必备的实用jQuery代码段+ 可以直接拿来用的15个jQuery代码片段
- Netty实现消息推送以及内部心跳机制
- kindle 不能连接wifi的三个原因
- 考研
- codeforces 724G. Xor-matic Number of the Graph
- PAT (Advanced Level) Practise 1092
- vue.js
- java多线程状态详解
- SpringBoot执行流程
- 关于N!的几个问题