netty 使用Java序列化
package com.zhaowb.netty.ch7_1; import java.io.Serializable; public class SubscribeReq implements Serializable { private static final long serialVersionUID = 1L; private int subReqID; private String userName; private String productName; private String phoneNumber; private String address; public SubscribeReq() { } public SubscribeReq(int subReqID, String userName, String productName, String phoneNumber, String address) { this.subReqID = subReqID; this.userName = userName; this.productName = productName; this.phoneNumber = phoneNumber; this.address = address; } public int getSubReqID() { return subReqID; } public void setSubReqID(int subReqID) { this.subReqID = subReqID; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "SubscribeReq{" + "subReqID=" + subReqID + ", userName='" + userName + '\'' + ", productName='" + productName + '\'' + ", phoneNumber='" + phoneNumber + '\'' + ", address='" + address + '\'' + '}'; } }
package com.zhaowb.netty.ch7_1; import java.io.Serializable; public class SubscribeResp implements Serializable { private static final long serialVersionUID = 1L; private int subReqID; private int respCode; private String desc; public SubscribeResp() { } public SubscribeResp(int subReqID, int respCode, String desc) { this.subReqID = subReqID; this.respCode = respCode; this.desc = desc; } public int getSubReqID() { return subReqID; } public void setSubReqID(int subReqID) { this.subReqID = subReqID; } public int getRespCode() { return respCode; } public void setRespCode(int respCode) { this.respCode = respCode; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } @Override public String toString() { return "SubscribeResp{" + "subReqID=" + subReqID + ", respCode=" + respCode + ", desc='" + desc + '\'' + '}'; } }
package com.zhaowb.netty.ch7_1; import com.zhaowb.netty.ch5_2.EchoServerHandler; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; public class SubReqServer { public void bind(int port) throws Exception { // 配置 服务端的 NIO 线程组 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 1024) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // 创建一个 ObjectDecoder ,负责对实现 Serializable 的 POJO 对象进行解码。 // 有多个构造函数,支持不同的ClassResolver,使用weakCachingConcurrentResolver创建线程安全的 // WeakReferenceMap 对类加载器进行缓存,支持多线程并发访问,当虚拟机内存不足时,会释放缓存中 // 的内存,防止内存泄漏,为了防止异常码流和解码错误导致的内存溢出,将单个对象最大序列化后的 // 字节数组长度设置为 1M ch.pipeline().addLast(new ObjectDecoder(1024 * 1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); // 创建 ObjectEncoder ,可以在消息发送的时候自动将实现 Serializable 的POJO 对象进行编码, // 无需对对象手动序列化,只需要关注自己的业务逻辑处理即可,对象序列化和发序列化都由netty的对象编码解码器完成。 ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new SubReqServerHandler()); } }); // 绑定端口,同步等待成功。 ChannelFuture f = b.bind(port).sync(); // 等待服务端监听端口关闭。 f.channel().closeFuture().sync(); } catch (Exception e) { // 退出,释放线程池资源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { } } new SubReqServer().bind(port); } }
package com.zhaowb.netty.ch7_1; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; @ChannelHandler.Sharable public class SubReqServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { SubscribeReq req = (SubscribeReq)msg; if( "lilinfeng".equals(req.getUserName())){ System.out.println("Server accept client subscribe req : [" + req.toString() + "]"); ctx.writeAndFlush(resp(req.getSubReqID())); } } public SubscribeResp resp( int subReqID){ SubscribeResp resp = new SubscribeResp(); resp.setSubReqID(subReqID); resp.setRespCode(10); resp.setDesc("Netty book order successd ,3 days later, sent to the designated address"); return resp; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close();// 发送异常,关闭链路 } }
package com.zhaowb.netty.ch7_1; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; import io.netty.handler.codec.serialization.ObjectDecoder; import io.netty.handler.codec.serialization.ObjectEncoder; public class SubReqClient { public void connect(int port, String host) throws Exception { //配置客户端 NIO 线程组 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ObjectDecoder(1024*1024,ClassResolvers.cacheDisabled(this.getClass().getClassLoader()))); ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new SubReqClientHandler()); } }); // 发起异步连接操作 ChannelFuture f = b.connect(host, port).sync(); // 等待客户端链路关闭 f.channel().closeFuture().sync(); } finally { // 释放 NIO 线程组 group.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; if (args != null && args.length > 0) { try { port = Integer.valueOf(args[0]); } catch (NumberFormatException e) { } } new SubReqClient().connect(port, "127.0.0.1"); } }
package com.zhaowb.netty.ch7_1; import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class SubReqClientHandler extends ChannelHandlerAdapter { public SubReqClientHandler() { } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { for (int i=0;i<10;i++){ ctx.write(subResp(i)); } ctx.flush(); } private SubscribeReq subResp(int i){ SubscribeReq req = new SubscribeReq(); req.setAddress("国家地质公园"); req.setPhoneNumber("5464654113"); req.setProductName("netty 权威指南"); req.setSubReqID(i); req.setUserName("lilinfeng"); return req; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("Receive server response : [" + msg + "]"); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }