• Netty实现简单群聊


    场景

    使用Netty实现简单群聊。服务端实现监控客户端上下线及通知、群聊消息转发。

    实现

    客户端与服务端使用String类型的消息进行发送与接收,因此客户端与服务端需要首先添加Netty封装的用于网络传输的编码解密处理器,否则将无法成功打印消息。

    .childHandler(new ChannelInitializer<SocketChannel>() {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            //字符串解码器,用于将通过ByteBuf传输的数据转换成String
            pipeline.addLast("decoder", new StringDecoder());
            //字符串编码器,用于将String编码到ByteBuf中进行网络传输
            pipeline.addLast("encoder", new StringEncoder());
            pipeline.addLast(new ServerHandler());
        }
    });
    

    服务端

    package others.netty.groupChat;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    
    /**
     * Netty群聊服务端实现
     * 根据不同事件驱动通知客户端 上下线状态,消息转发
     *
     * @author makeDoBetter
     * @version 1.0
     * @date 2021/4/25 10:36
     * @since JDK 1.8
     */
    public class Sever {
        private int port;
    
        public Sever(int port) {
            this.port = port;
        }
    
        public void run(){
            NioEventLoopGroup boss = new NioEventLoopGroup(1);
            NioEventLoopGroup worker = new NioEventLoopGroup();
            ServerBootstrap sever = new ServerBootstrap();
            try {
                sever.group(boss, worker)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE ,true)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                //字符串解码器,用于将通过ByteBuf传输的数据转换成String
                                pipeline.addLast("decoder", new StringDecoder());
                                //字符串编码器,用于将String编码到ByteBuf中进行网络传输
                                pipeline.addLast("encoder", new StringEncoder());
                                pipeline.addLast(new ServerHandler());
                            }
                        });
                ChannelFuture channelFuture = sever.bind(port).sync();
                //添加一个监听器
                channelFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()){
                            System.out.println("服务端启动完成");
                        } else {
                            System.out.println("服务端启动失败");
                        }
                    }
                });
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                boss.shutdownGracefully();
                worker.shutdownGracefully();
            }
    
        }
    
        public static void main(String[] args) {
            new Sever(1234).run();
        }
    }
    
    

    自定义服务处理器,用于处理客户端连接与断开、消息转发等。

    package others.netty.groupChat;
    
    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;
    
    /**
     * 实现客户端上下线状态、消息通知
     *
     * @author makeDoBetter
     * @version 1.0
     * @date 2021/4/25 10:47
     * @since JDK 1.8
     */
    public class ServerHandler extends SimpleChannelInboundHandler<String> {
        /**
         * 定义一个全局的单线程的静态变量,用于存储整个连接的客户端集合
         */
        private static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            Channel channel = ctx.channel();
            //不需要遍历,group可以直接处理
            group.writeAndFlush("[客户端]" + channel.remoteAddress() + "上线");
            group.add(channel);
            System.out.println(group.toString());
        }
    
        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            Channel channel = ctx.channel();
            //不需要手动remove()当前channel,group会自动剔除离线channel
            group.writeAndFlush("[客户端]" + channel.remoteAddress() + "下线");
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            Channel self = ctx.channel();
            //实现消息的转发,忽略自身
            group.forEach(channel -> {
                if (self != channel) {
                    System.out.println(msg + "发送到客户端" + channel.remoteAddress());
                    channel.writeAndFlush("[客户端]" + self.remoteAddress() + "说:" + msg + "
    ");
                }
            });
        }
    }
    
    

    客户端

    package others.netty.groupChat;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.Channel;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelFutureListener;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import io.netty.handler.codec.string.StringDecoder;
    import io.netty.handler.codec.string.StringEncoder;
    
    import java.util.Scanner;
    
    /**
     * 客户端实现服务端连接,消息发送、接收打印
     *
     * @author makeDoBetter
     * @version 1.0
     * @date 2021/4/25 11:23
     * @since JDK 1.8
     */
    public class Client {
        private String host;
        private int port;
    
        public Client(String host, int port) {
            this.host = host;
            this.port = port;
        }
    
        public void run(){
            NioEventLoopGroup group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                //字符串解码器,用于将通过ByteBuf传输的数据转换成String
                                pipeline.addLast("decoder", new StringDecoder());
                                //字符串编码器,用于将String编码到ByteBuf中进行网络传输
                                pipeline.addLast("encoder", new StringEncoder());
                                pipeline.addLast(new ClientHandler());
                            }
                        });
                ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
                channelFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()){
                            System.out.println("====连接成功=====");
                        } else {
                            System.out.println("客户端连接失败");
                        }
                    }
                });
                Channel channel = channelFuture.channel();
                Scanner scanner = new Scanner(System.in);
                while (scanner.hasNextLine()){
                    String line = scanner.nextLine();
                    channel.writeAndFlush(line);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
        }
    
        public static void main(String[] args) {
            new Client("127.0.0.1", 1234).run();
        }
    }
    
    

    客户端处理程序,打印转发到当前客户端的消息。

    package others.netty.groupChat;
    
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.SimpleChannelInboundHandler;
    
    /**
     * 客户端读取数据事件
     *
     * @author makeDoBetter
     * @version 1.0
     * @date 2021/4/25 11:37
     * @since JDK 1.8
     */
    public class ClientHandler extends SimpleChannelInboundHandler<String> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            System.out.println(msg.trim());
        }
    }
    
    

  • 相关阅读:
    ISO/IEC 9899:2011 条款5——5.2.2 字符显示语义
    ISO/IEC 9899:2011 条款5——5.2.1 字符集
    ISO/IEC 9899:2011 条款5——5.2 环境上的考虑
    nVidia GPGPU vs AMD Radeon HD Graphics执行模式对比
    ISO/IEC 9899:2011 条款5——5.1.2 执行环境
    ISO/IEC 9899:2011 条款5——5.1.1 翻译环境
    ISO/IEC 9899:2011 条款5——5.1 概念模型
    ISO/IEC 9899:2011 条款5——环境
    ISO/IEC 9899:2011 条款4——标准顺从
    php利用phpexcel导出数据
  • 原文地址:https://www.cnblogs.com/fjrgg/p/14721325.html
Copyright © 2020-2023  润新知