如何使用netty实现聊天业务功能

2023年 9月 23日 70.7k 0

业务背景

在项目中需要用到即时通讯业务,比如聊天应用或实时通知应用。在这种应用中,客户端和服务器之间需要保持持久的连接,以实现实时消息的传递。

具体来说,在聊天应用中,当用户登录应用时,客户端会与服务器建立一个长连接。通过这个长连接,服务器可以向客户端推送新消息,并且客户端也可以发送消息给其他用户或群组。这种实时的双向通信需要使用长连接来实现。

使用Netty实现长连接可以提供以下优势:

  • 高性能:Netty是一个高性能的网络编程框架,采用异步事件驱动模型,可以处理大量并发连接,并且具有低延迟和高吞吐量。
  • 可扩展性:Netty提供了灵活的线程模型和事件处理机制,可以轻松地进行系统的扩展和定制,满足不同规模和需求的应用。
  • 协议支持:Netty支持多种网络协议,如TCP、UDP、HTTP等,并提供了一组丰富的编解码器,便于处理不同协议的数据格式。
  • 多平台兼容性:Netty支持跨平台开发,可以在不同的操作系统和设备上运行,包括服务器、桌面应用和移动应用。
  • 使用Netty实现长连接的聊天应用可以满足用户对实时通信的需求,提供即时的消息交互和通知功能。通过长连接,用户可以接收到其他用户发送的消息,并且可以实时地与其他用户进行沟通和交流。这样的应用场景包括在线客服系统、社交网络应用、团队协作工具等。

    netty实现聊天的逻辑

    Netty实现简单聊天逻辑的Java代码示例:

  • 创建Netty服务器和ChannelHandler:
  • public class NettyServer {
        private static final int PORT = 8888;
    
        public static void main(String[] args) throws InterruptedException {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
    
            try {
                ServerBootstrap bootstrap = new ServerBootstrap()
                        .group(bossGroup, workerGroup)
                        .channel(NioServerSocketChannel.class)
                        .childHandler(new ChannelInitializer() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                                pipeline.addLast(new StringDecoder());
                                pipeline.addLast(new StringEncoder());
                                pipeline.addLast(new ChatServerHandler());
                            }
                        });
    
                ChannelFuture future = bootstrap.bind(PORT).sync();
                System.out.println("Server started on port " + PORT);
                future.channel().closeFuture().sync();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    
    @ChannelHandler.Sharable
    public class ChatServerHandler extends SimpleChannelInboundHandler {
        private static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            Channel incoming = ctx.channel();
            System.out.println("Client connected: " + incoming.remoteAddress());
            channelGroup.add(incoming);
        }
    
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            Channel incoming = ctx.channel();
            System.out.println("Client disconnected: " + incoming.remoteAddress());
            channelGroup.remove(incoming);
        }
    
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            Channel incoming = ctx.channel();
            System.out.println("Received message from " + incoming.remoteAddress() + ": " + msg);
    
            // 广播消息给所有客户端
            for (Channel channel : channelGroup) {
                if (channel != incoming) {
                    channel.writeAndFlush("[" + incoming.remoteAddress() + "]: " + msg + "\n");
                } else {
                    channel.writeAndFlush("[You]: " + msg + "\n");
                }
            }
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            Channel incoming = ctx.channel();
            System.err.println("Client " + incoming.remoteAddress() + " encountered an error.");
            cause.printStackTrace();
            ctx.close();
        }
    }
    
    
  • 创建Netty客户端:
  • public class NettyClient {
        private static final String HOST = "localhost";
        private static final int PORT = 8888;
    
        public static void main(String[] args) throws InterruptedException {
            EventLoopGroup group = new NioEventLoopGroup();
    
            try {
                Bootstrap bootstrap = new Bootstrap()
                        .group(group)
                        .channel(NioSocketChannel.class)
                        .handler(new ChannelInitializer() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                                pipeline.addLast(new StringDecoder());
                                pipeline.addLast(new StringEncoder());
                                pipeline.addLast(new ChatClientHandler());
                            }
                        });
    
                Channel channel = bootstrap.connect(HOST, PORT).sync().channel();
                BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
                while (true) {
                    String msg = reader.readLine();
                    if (msg == null || "quit".equalsIgnoreCase(msg)) {
                        break;
                    }
                    channel.writeAndFlush(msg + "\n");
                }
            } finally {
                group.shutdownGracefully();
            }
        }
    }
    
    @ChannelHandler.Sharable
    public class ChatClientHandler extends SimpleChannelInboundHandler {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
            System.out.println(msg);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }
    
    

    Netty服务器和客户端都通过\n作为分隔符进行消息的解码和编码。当服务器接收到一个消息时,它会将消息广播给所有连接的客户端。客户端可以通过控制台输入消息,并将其发送到服务器。

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论