从零学Netty(七)Netty实现 多人聊天室

实例demo

编写服务端

/**
 * 服务端
 *
 * @author LionLi
 */
public class GroupChatServer {

    private final int port;

    public GroupChatServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {

        // boss组 使用一个线程接收和分发请求
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // worker工作组 默认线程数8 处理实际请求
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    // 主线程处理类
                    .channel(NioServerSocketChannel.class)
                    // 针对主线程的配置 分配线程最大数量 128
                    .option(ChannelOption.SO_BACKLOG, 128)
                    // 针对子线程的配置 保持长连接
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    // 子线程处理类
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 加入 编解码handler
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            // 加入自己的业务处理handler
                            pipeline.addLast(new GroupChatServerHandler());
                        }
                    });

            System.out.println("服务器正在监听......");
            ChannelFuture channelFuture = b.bind(port).sync();

            // 监听关闭
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws Exception {
        new GroupChatServer(8088).run();
    }
}

编写服务端业务处理器

/**
 * 服务端业务处理器
 *
 * @author LionLi
 */
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {

    /**
     * 定义一个channle 组,管理所有的channel
     * GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例
     * 内部使用ConcurrentHashMap管理,线程安全
     */
    private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 初始化连接事件
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        CHANNEL_GROUP.add(channel);
    }

    /**
     * 连接断开事件
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        System.out.println("聊天室人数:" + CHANNEL_GROUP.size());
    }

    /**
     * 通道新增事件
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        System.out.println(ctx.channel().remoteAddress() + " 上线了");
    }

    /**
     * 通道关闭事件
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        System.out.println(ctx.channel().remoteAddress() + " 离线了");
    }

    /**
     * 读取数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
        CHANNEL_GROUP.writeAndFlush(msg);
    }

    /**
     * 异常事件
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        //关闭通道
        ctx.close();
    }
}

编写客户端

/**
 * 客户端
 *
 * @author LionLi
 */
public class GroupChatClient {

    private final String host;
    private final int port;
    private final String username;

    public GroupChatClient(String host, int port, String username) {
        this.host = host;
        this.port = port;
        this.username = username;
    }

    public void run() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            //加入 编解码handler
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            //加入自定义的handler
                            pipeline.addLast(new GroupChatClientHandler());
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            Channel channel = channelFuture.channel();

            channel.writeAndFlush(username + " 上线了");

            //客户端需要输入信息,创建一个扫描器
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()) {
                String msg = scanner.nextLine();
                if ("exit".equals(msg)) {
                    channel.writeAndFlush(username + " 离开了");
                    break;
                } else {
                    channel.writeAndFlush(username + ":" + msg);
                }
            }
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.print("请输入用户名: ");
        Scanner scanner = new Scanner(System.in);
        String username = scanner.nextLine();
        new GroupChatClient("localhost", 8088, username).run();
    }
}

编写客户端业务处理器

/**
 * 客户端业务处理器
 *
 * @author LionLi
 */
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {

    /**
     * 读取数据
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) {
        System.out.println(msg.trim());
    }
}

测试

  • 场景如下:
  • 启动服务端
  • 顺序启动客户端 群友ABC 并输入用户名
  • 分别打招呼
  • 倒序退出客户端 群友ABC

 

 

项目已上传到gitee

地址: netty-demo

如果帮到您了,请帮忙点个star

猜你喜欢

转载自blog.csdn.net/weixin_40461281/article/details/109096749