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 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 + "]"; } }
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 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 + "]"; } }
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) { // 服务器线程组 用于网络事件的处理 一个用于服务器接收客户端的连接 // 另一个线程组用于处理SocketChannel的网络读写 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //NIO服务器端的辅助启动类 降低服务器开发难度 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // 类似NIO中serverSocketChannel .option(ChannelOption.SO_BACKLOG, 100) // 配置TCP参数 .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ObjectDecoder(1024*1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); //objectdecoder ch.pipeline().addLast(new ObjectEncoder()); //objectdecoder ch.pipeline().addLast(new SubReqServerHandler()); } } ); // 最后绑定I/O事件的处理类 // 服务器启动后 绑定监听端口 同步等待成功 主要用于异步操作的通知回调 回调处理用的ChildChannelHandler ChannelFuture f = b.bind(port).sync(); System.out.println("The time Server is start : "+port); // 等待服务端监听端口关闭 f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ // 优雅退出 释放线程池资源 workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); System.out.println("服务器优雅的释放了线程资源..."); } } public static void main(String[] args) { int port = 8080; if(null != args && args.length > 0) { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { e.printStackTrace(); } } new SubReqServer().bind(port); } }
import io.netty.channel.ChannelHandlerAdapter; import io.netty.channel.ChannelHandlerContext; public class SubReqServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { SubscribeReq req = (SubscribeReq)msg; if("kobe".equalsIgnoreCase(req.getUserName())) { System.out.println("Service accept client subscribe req : ["+req.toString()+"]"); ctx.writeAndFlush(resp(req.getSubReqID())); } } private Object resp(int subReqID) { SubscribeResp resp = new SubscribeResp(); resp.setSubReqID(subReqID); resp.setRespCode(0); resp.setDesc("kobe is receive order, 3 days later, send to the address"); return resp; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } }
import io.netty.bootstrap.Bootstrap; 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; /** * client * @author * */ public class SubReqClient { /** * 连接服务器 * @param host * @param port */ public void connect(String host, int port) { //配置客户端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.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); ch.pipeline().addLast(new ObjectEncoder()); ch.pipeline().addLast(new SubReqClientHandler()); } }); //异步链接服务器 同步等待链接成功 ChannelFuture f = b.connect(host, port).sync(); //等待链接关闭 f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ group.shutdownGracefully(); System.out.println("客户端优雅的释放了线程资源..."); } } public static void main(String[] args) { int port = 8080; if(null != args && args.length > 0) { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { e.printStackTrace(); } } new SubReqClient().connect("127.0.0.1", port); } }
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(subReq(i)); } ctx.flush(); } private SubscribeReq subReq(int i) { SubscribeReq subscribeReq = new SubscribeReq(); subscribeReq.setSubReqID(i); subscribeReq.setUserName("kobe"); subscribeReq.setProductName("effect in java"); subscribeReq.setPhoneNumber("13875XXXXXX"); subscribeReq.setAddress("广东深圳南山"); return subscribeReq; } @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(); } }
Netty的ObjectEncoder编码器可以自动对订购应答消息进行序列化,然后发送给客户端,客户端的ObjectDecoder解码器对码流进行反序列化,获得订购请求应答消息。