• Netty编程案例


    准备:引入netty依赖

            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-all</artifactId>
                <version>4.1.8.Final</version>
            </dependency>

    入门案例:

    1.服务端业务处理类

    package com.tenpower.netty.basic;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.util.CharsetUtil;
    
    //服务器端的业务处理类
    public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    
        //读取数据事件
        public void channelRead(ChannelHandlerContext ctx,Object msg){
            System.out.println("Server:"+ctx);
            ByteBuf buf=(ByteBuf) msg;
            System.out.println("客户端发来的消息:"+buf.toString(CharsetUtil.UTF_8));
        }
    
        //数据读取完毕事件
        public void channelReadComplete(ChannelHandlerContext ctx){
            ctx.writeAndFlush(Unpooled.copiedBuffer("就是没钱",CharsetUtil.UTF_8));
        }
    
        //异常发生事件
        public void exceptionCaught(ChannelHandlerContext ctx,Throwable t){
            ctx.close();
        }
    
    }

    2.服务端程序。配置线程组、自定义业务处理类,并绑定了端口号启动

    package com.tenpower.netty.basic;
    
    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;
    
    public class NettyServer {
        public static void main(String[] args) throws Exception{
    
            //1. 创建一个线程组:接收客户端连接
            EventLoopGroup bossGroup =new NioEventLoopGroup();
            //2. 创建一个线程组:处理网络操作
            EventLoopGroup workerGroup =new NioEventLoopGroup();
            //3. 创建服务器端启动助手来配置参数
            ServerBootstrap b=new ServerBootstrap();
            b.group(bossGroup,workerGroup) //4.设置两个线程组
             .channel(NioServerSocketChannel.class) //5.使用NioServerSocketChannel作为服务器端通道的实现
             .option(ChannelOption.SO_BACKLOG,128) //6.设置线程队列中等待连接的个数
             .childOption(ChannelOption.SO_KEEPALIVE,true) //7.保持活动连接状态
             .childHandler(new ChannelInitializer<SocketChannel>() {  //8. 创建一个通道初始化对象
                 public void initChannel(SocketChannel sc){   //9. 往Pipeline链中添加自定义的handler类
                     sc.pipeline().addLast(new NettyServerHandler());
                 }
             });
            System.out.println("......Server is ready......");
            ChannelFuture cf=b.bind(9999).sync();  //10. 绑定端口 bind方法是异步的  sync方法是同步阻塞的
            System.out.println("......Server is starting......");
    
            //11. 关闭通道,关闭线程组
            cf.channel().closeFuture().sync(); //异步
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    3.客户端业务处理类

    package com.tenpower.netty.basic;
    
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import io.netty.util.CharsetUtil;
    
    //客户端业务处理类
    public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    
        //通道就绪事件
        public void channelActive(ChannelHandlerContext ctx){
            System.out.println("Client:"+ctx);
            ctx.writeAndFlush(Unpooled.copiedBuffer("老板,还钱吧",CharsetUtil.UTF_8));
        }
    
        //读取数据事件
        public void channelRead(ChannelHandlerContext ctx,Object msg){
            ByteBuf buf=(ByteBuf) msg;
            System.out.println("服务器端发来的消息:"+buf.toString(CharsetUtil.UTF_8));
        }
    
    }

    4.客户端程序。配置线程组、自定义业务处理类,并启动连接服务端

    package com.tenpower.netty.basic;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    
    //网络客户端
    public class NettyClient {
        public static void main(String[] args) throws  Exception{
    
            //1. 创建一个线程组
            EventLoopGroup group=new NioEventLoopGroup();
            //2. 创建客户端的启动助手,完成相关配置
            Bootstrap b=new Bootstrap();
            b.group(group)  //3. 设置线程组
             .channel(NioSocketChannel.class)  //4. 设置客户端通道的实现类
             .handler(new ChannelInitializer<SocketChannel>() {  //5. 创建一个通道初始化对象
                 @Override
                 protected void initChannel(SocketChannel socketChannel) throws Exception {
                     socketChannel.pipeline().addLast(new NettyClientHandler()); //6.往Pipeline链中添加自定义的handler
                 }
             });
            System.out.println("......Client is  ready......");
    
            //7.启动客户端去连接服务器端  connect方法是异步的   sync方法是同步阻塞的
            ChannelFuture cf=b.connect("127.0.0.1",9999).sync();
    
            //8.关闭连接(异步非阻塞)
            cf.channel().closeFuture().sync();
    
        }
    }

    运行结果如下图:

    网络聊天案例:

    1.自定义服务端业务处理类。通道就绪时,输出在线;通道未就绪时,输出下线;通道发数据时,读数据

    package com.tenpower.netty.chat;
    
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.group.ChannelGroup;
    import io.netty.channel.group.DefaultChannelGroup;
    import io.netty.util.concurrent.GlobalEventExecutor;
    
    import java.util.ArrayList;
    import java.util.List;
    
    //自定义一个服务器端业务处理类
    public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
    
        public static List<Channel> channels = new ArrayList<>();
    
        @Override  //通道就绪
        public void channelActive(ChannelHandlerContext ctx)  {
            Channel inChannel=ctx.channel();
            channels.add(inChannel);
            System.out.println("[Server]:"+inChannel.remoteAddress().toString().substring(1)+"上线");
        }
        @Override  //通道未就绪
        public void channelInactive(ChannelHandlerContext ctx)  {
            Channel inChannel=ctx.channel();
            channels.remove(inChannel);
            System.out.println("[Server]:"+inChannel.remoteAddress().toString().substring(1)+"离线");
        }
        @Override  //读取数据
        protected void channelRead0(ChannelHandlerContext ctx, String s)  {
            Channel inChannel=ctx.channel();
            for(Channel channel:channels){
                if(channel!=inChannel){
                    channel.writeAndFlush("["+inChannel.remoteAddress().toString().substring(1)+"]"+"说:"+s+"
    ");
                }
            }
        }
    
    }

    2.服务端程序。往Pipeline链中添加的处理字符串的编码器和解码器加入Pipeline后会自动工作,这样在服务端读写字符串数据时无需人工处理ByteBuf

    package com.tenpower.netty.chat;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.codec.DelimiterBasedFrameDecoder;
    import io.netty.handler.codec.Delimiters;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    
    //聊天程序服务器端
    public class ChatServer {
    
        private int port; //服务器端端口号
    
        public ChatServer(int port) {
            this.port = port;
        }
    
        public void run() throws Exception {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
                b.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE, true)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) {
                                ChannelPipeline pipeline=ch.pipeline();
                                //往pipeline链中添加一个解码器
                                pipeline.addLast("decoder",new StringDecoder());
                                //往pipeline链中添加一个编码器
                                pipeline.addLast("encoder",new StringEncoder());
                                //往pipeline链中添加自定义的handler(业务处理类)
                                pipeline.addLast(new ChatServerHandler());
            }
        });
                System.out.println("Netty Chat Server启动......");
        ChannelFuture f = b.bind(port).sync();
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
                System.out.println("Netty Chat Server关闭......");
            }
        }
    
        public static void main(String[] args) throws Exception {
            new ChatServer(9999).run();
        }
    }

    3.客户端业务处理类。读取服务端发来的数据

    package com.tenpower.netty.chat;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    //自定义一个客户端业务处理类
    public class ChatClientHandler extends SimpleChannelInboundHandler<String> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
            System.out.println(s.trim());
        }
    }

    4.客户端程序。也添加了编解码器

    package com.tenpower.netty.chat;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.*;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.DelimiterBasedFrameDecoder;
    import io.netty.handler.codec.Delimiters;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.util.Scanner;
    
    //聊天程序客户端
    public class ChatClient {
        private final String host; //服务器端IP地址
        private final int port;  //服务器端端口号
    
        public ChatClient(String host, int port) {
            this.host = host;
            this.port = port;
        }
    
        public void run(){
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap()
                        .group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch){
                                ChannelPipeline pipeline=ch.pipeline();
                                //往pipeline链中添加一个解码器
                                pipeline.addLast("decoder",new StringDecoder());
                                //往pipeline链中添加一个编码器
                                pipeline.addLast("encoder",new StringEncoder());
                                //往pipeline链中添加自定义的handler(业务处理类)
                                pipeline.addLast(new ChatClientHandler());
                            }
                        });
    
                ChannelFuture cf=bootstrap.connect(host,port).sync();
                Channel channel=cf.channel();
                System.out.println("------"+channel.localAddress().toString().substring(1)+"------");
                Scanner scanner=new Scanner(System.in);
                while (scanner.hasNextLine()){
                    String msg=scanner.nextLine();
                    channel.writeAndFlush(msg+"
    ");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) throws Exception {
            new ChatClient("127.0.0.1",9999).run();
        }
    }

    可同时运行多个客户端,运行结果如下:

    自定义RPC案例:

    ● 服务提供方,两个接口和两个实现类共消费方调用

    public interface HelloNetty {
        String hello();
    }
    
    public class HelloNettyImpl implements HelloNetty {
        @Override
        public String hello() {
            return "hello,netty";
        }
    }
    
    public interface HelloRPC {
        String hello(String name);
    }
    
    public class HelloRPCImpl implements HelloRPC {
        @Override
        public String hello(String name) {
            return "hello," + name;
        }
    }

    ● Server Stub

    1.封装消费方发起远程调用时传给服务方的数据

    package com.tenpower.rpc.serverStub;
    
    import java.io.Serializable;
    
    //封装类信息
    public class ClassInfo implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private String className;  //类名
        private String methodName;//方法名
        private Class<?>[] types; //参数类型
        private Object[] objects;//参数列表
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
    
        public String getMethodName() {
            return methodName;
        }
    
        public void setMethodName(String methodName) {
            this.methodName = methodName;
        }
    
        public Class<?>[] getTypes() {
            return types;
        }
    
        public void setTypes(Class<?>[] types) {
            this.types = types;
        }
    
        public Object[] getObjects() {
            return objects;
        }
    
        public void setObjects(Object[] objects) {
            this.objects = objects;
        }
    }

    2.业务处理类。读取消费方发来的数据并调用本地,然后把结果返回消费方

    package com.tenpower.rpc.serverStub;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInboundHandlerAdapter;
    import org.reflections.Reflections;
    
    import java.lang.reflect.Method;
    import java.util.Set;
    
    //服务器端业务处理类
    public class InvokeHandler extends ChannelInboundHandlerAdapter {
        //得到某接口下某个实现类的名字
        private String getImplClassName(ClassInfo classInfo) throws Exception{
            //服务方接口和实现类所在的包路径
            String interfacePath="com.tenpower.rpc.server";
            int lastDot = classInfo.getClassName().lastIndexOf(".");
            String interfaceName=classInfo.getClassName().substring(lastDot);
            Class superClass=Class.forName(interfacePath+interfaceName);
            Reflections reflections = new Reflections(interfacePath);
            //得到某接口下的所有实现类
            Set<Class> ImplClassSet=reflections.getSubTypesOf(superClass);
            if(ImplClassSet.size()==0){
                System.out.println("未找到实现类");
                return null;
            }else if(ImplClassSet.size()>1){
                System.out.println("找到多个实现类,未明确使用哪一个");
                return null;
            }else {
                //把集合转换为数组
                Class[] classes=ImplClassSet.toArray(new Class[0]);
                return classes[0].getName(); //得到实现类的名字
            }
        }
    
        @Override  //读取客户端发来的数据并通过反射调用实现类的方法
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            ClassInfo classInfo = (ClassInfo) msg;
            Object clazz = Class.forName(getImplClassName(classInfo)).newInstance();
            Method method = clazz.getClass().getMethod(classInfo.getMethodName(), classInfo.getTypes());
            //通过反射调用实现类的方法
            Object result = method.invoke(clazz, classInfo.getObjects());
            ctx.writeAndFlush(result);
        }
    }

    3.网络服务器。采用Netty自带的ObjectEncoder和ObjectDecoder作为编解码器

    package com.tenpower.rpc.serverStub;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.*;
    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;
    
    //网络处理服务器
    public class NettyRPCServer {
        private int port;
        public NettyRPCServer(int port) {
            this.port = port;
        }
    
        public void start() {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE, true)
                        .localAddress(port).childHandler(
                                new ChannelInitializer<SocketChannel>() {
                                    @Override
                                    protected void initChannel(SocketChannel ch) throws Exception {
                                        ChannelPipeline pipeline = ch.pipeline();
                                        //编码器
                                        pipeline.addLast("encoder", new ObjectEncoder());
                                        //解码器
                                        pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                                        //服务器端业务处理类
                                        pipeline.addLast(new InvokeHandler());
                                    }
                                });
                ChannelFuture future = serverBootstrap.bind(port).sync();
                System.out.println("......server is ready......");
                future.channel().closeFuture().sync();
            } catch (Exception e) {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) throws Exception {
            new NettyRPCServer(9999).start();
        }
    }

    ● Client Stub

    1.客户端业务处理类。读取远程调用返回的数据

    package com.tenpower.rpc.clientStub;
    
    import io.netty.channel.*;
    
    //客户端业务处理类
    public class ResultHandler extends ChannelInboundHandlerAdapter {
    
        private Object response;
        public Object getResponse() {
            return response;
        }
    
        @Override //读取服务器端返回的数据(远程调用的结果)
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            response = msg;
            ctx.close();
        }
    }

    2.客户端代理类

    package com.tenpower.rpc.clientStub;
    
    import com.tenpower.rpc.serverStub.ClassInfo;
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.*;
    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;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    //客户端代理类
    public class NettyRPCProxy {
        //根据接口创建代理对象
        public static Object create(Class target) {
            return Proxy.newProxyInstance(target.getClassLoader(), new Class[]{target}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    //封装ClassInfo
                    ClassInfo classInfo = new ClassInfo();
                    classInfo.setClassName(target.getName());
                    classInfo.setMethodName(method.getName());
                    classInfo.setObjects(args);
                    classInfo.setTypes(method.getParameterTypes());
    
                    //开始用Netty发送数据
                    EventLoopGroup group = new NioEventLoopGroup();
                    ResultHandler resultHandler = new ResultHandler();
                    try {
                        Bootstrap b = new Bootstrap();
                        b.group(group)
                                .channel(NioSocketChannel.class)
                                .handler(new ChannelInitializer<SocketChannel>() {
                                    @Override
                                    public void initChannel(SocketChannel ch) throws Exception {
                                        ChannelPipeline pipeline = ch.pipeline();
                                        //编码器
                                        pipeline.addLast("encoder", new ObjectEncoder());
                                        //解码器  构造方法第一个参数设置二进制数据的最大字节数  第二个参数设置具体使用哪个类解析器
                                        pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                                        //客户端业务处理类
                                        pipeline.addLast("handler", resultHandler);
                                    }
                                });
                        ChannelFuture future = b.connect("127.0.0.1", 9999).sync();
                        future.channel().writeAndFlush(classInfo).sync();
                        future.channel().closeFuture().sync();
                    } finally {
                        group.shutdownGracefully();
                    }
                    return resultHandler.getResponse();
                }
            });
        }
    }

    ● Client

    package com.tenpower.rpc.client;
    
    import com.tenpower.rpc.clientStub.NettyRPCProxy;
    
    //服务调用方
    public class TestNettyRPC {
        public static void main(String [] args){
    
            //第1次远程调用
            HelloNetty helloNetty=(HelloNetty) NettyRPCProxy.create(HelloNetty.class);
            System.out.println(helloNetty.hello());
    
            //第2次远程调用
            HelloRPC helloRPC =  (HelloRPC) NettyRPCProxy.create(HelloRPC.class);
            System.out.println(helloRPC.hello("RPC"));
    
        }
    }

     运行结果如下:

    使用google的ProtoBuf作为编解码器:

    1.引入依赖

            <dependency>
                <groupId>com.google.protobuf</groupId>
                <artifactId>protobuf-java</artifactId>
                <version>3.6.1</version>
            </dependency>

    2.proto文件

     3.通过protoc.exe生成java文件

     注意:不要编辑这个类,该类的内部类才是真正的POJO

    4.客户端程序。在Pipeline链中添加ProtoBufEncoder编码器对象

    public class NettyClient {
    
        public static void main(String[] args) throws Exception {
            EventLoopGroup group = new NioEventLoopGroup();
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel sc) {
                            sc.pipeline().addLast("encoder",new ProtobufEncoder());
                            sc.pipeline().addLast(new NettyClientHandler());
                        }
                    });
    
            // 启动客户端
            ChannelFuture cf = b.connect("127.0.0.1", 9999).sync(); // (5)
    
            // 等待连接关闭
            cf.channel().closeFuture().sync();
        }
    }

    5.往服务器端发送POJO时可以使用生成的BookMessage

    public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            BookMessage.Book  book=BookMessage.Book.newBuilder().setId(1).setName("Java从入门到精通").build();
            ctx.writeAndFlush(book);
        }
    
    }

    6.服务端程序。要向Pipeline链中添加ProtoBufDecoder解码器对象

    public class NettyServer {
    
        public static void main(String[] args) throws Exception{
    
            EventLoopGroup pGroup = new NioEventLoopGroup(); //线程组:用来处理网络事件处理(接受客户端连接)
            EventLoopGroup cGroup = new NioEventLoopGroup(); //线程组:用来进行网络通讯读写
    
            ServerBootstrap b = new ServerBootstrap();
            b.group(pGroup, cGroup)
                    .channel(NioServerSocketChannel.class) //注册服务端channel
                    .option(ChannelOption.SO_BACKLOG, 128)
                    . childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        public void initChannel(SocketChannel sc) throws Exception {
                            sc.pipeline().addLast("decoder",new ProtobufDecoder(BookMessage.Book.getDefaultInstance()));
                            sc.pipeline().addLast(new NettyServerHandler());
                        }
                    });
            ChannelFuture cf = b.bind(9999).sync();
            System.out.println("......Server is Starting......");
    
            //释放
            cf.channel().closeFuture().sync();
            pGroup.shutdownGracefully();
            cGroup.shutdownGracefully();
        }
    }

    7.服务器端接收数据可直接把数据转换成POJO

    public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            BookMessage.Book book=(BookMessage.Book)msg;
            System.out.println("客户端发来数据:"+book.getName());
        }
    
    }
  • 相关阅读:
    基础实验7-2.2 插入排序还是堆排序 (25分)
    进阶实验6-3.1 红色警报 (25分)--并查集
    基础实验3-2.2 单链表分段逆转 (25分)--单链表
    基础实验6-2.2 汉密尔顿回路 (25分)--邻接矩阵
    案例6-1.3 哥尼斯堡的“七桥问题” (25分)--dfs图连通+度判断
    基础实验8-1.1 单身狗 (25分)
    基础实验7-2.3 德才论 (25分)--排序
    基础实验7-2.4 PAT排名汇总 (25分)--结构体排序(快排)
    进阶实验4-3.4 笛卡尔树 (25分)--二叉排序树+堆排序
    基础实验4-2.7 修理牧场 (25分)-堆+哈夫曼树
  • 原文地址:https://www.cnblogs.com/naixin007/p/14487643.html
Copyright © 2020-2023  润新知