Netty之实现一个简单的群聊系统
生活随笔
收集整理的這篇文章主要介紹了
Netty之实现一个简单的群聊系统
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
要求
編寫一個 Netty 群聊系統,實現服務器端和客戶端之間的數據簡單通訊(非阻塞)
實現多人群聊
服務器端:可以監測用戶上線,離線,并實現消息轉發功能
客戶端:通過channel可以無阻塞發送消息給其它所有用戶,同時可以接受其它用戶發送的消息(由服務器轉發得到)
代碼演示
服務端
public class GroupChatServer { ?private int port; ?public GroupChatServer(int port) {this.port = port;} ?/*** 編寫run方法,處理客戶端的請求** @throws Exception*/public void run() throws Exception { ?//創建兩個線程組EventLoopGroup bossGroup = new NioEventLoopGroup(1);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>() { ?@Overrideprotected void initChannel(SocketChannel ch) throws Exception { ?//獲取到pipelineChannelPipeline pipeline = ch.pipeline();//向pipeline加入解碼器pipeline.addLast("decoder", new StringDecoder());//向pipeline加入編碼器pipeline.addLast("encoder", new StringEncoder());//加入自己的業務處理handlerpipeline.addLast(new GroupChatServerHandler()); ?}}); ?System.out.println("netty 服務器啟動");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(7000).run();} }?
服務端業務處理類
public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> {//使用一個hashMap 管理//public static Map<String, Channel> channels = new HashMap<String,Channel>(); ?/*** 定義一個channel 組,管理所有的channel* GlobalEventExecutor.INSTANCE) 是全局的事件執行器,是一個單例*/private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ?/*** handlerAdded 表示連接建立,一旦連接,第一個被執行* 將當前channel 加入到 channelGroup** @param ctx* @throws Exception*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) throws Exception {Channel channel = ctx.channel();//將該客戶加入聊天的信息推送給其它在線的客戶端//該方法會將 channelGroup 中所有的channel 遍歷,并發送消息,我們不需要自己遍歷channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 加入聊天" + sdf.format(new java.util.Date()) + " \n");channelGroup.add(channel);} ?/*** 斷開連接, 將xx客戶離開信息推送給當前在線的客戶** @param ctx* @throws Exception*/@Overridepublic void handlerRemoved(ChannelHandlerContext ctx) throws Exception { ?Channel channel = ctx.channel();channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 離開了\n");System.out.println("channelGroup size" + channelGroup.size()); ?} ?/*** 表示channel 處于活動狀態, 提示 xx上線** @param ctx* @throws Exception*/@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception { ?System.out.println(ctx.channel().remoteAddress() + " 上線了~");} ?/*** 表示channel 處于不活動狀態, 提示 xx離線了** @param ctx* @throws Exception*/@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception { ?System.out.println(ctx.channel().remoteAddress() + " 離線了~");} ?/*** 讀取數據** @param ctx* @param msg* @throws Exception*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {//獲取到當前channelChannel channel = ctx.channel();//這時我們遍歷channelGroup, 根據不同的情況,回送不同的消息 ?channelGroup.forEach(ch -> {if (channel != ch) {//不是當前的channel,轉發消息ch.writeAndFlush("[客戶]" + channel.remoteAddress() + " 發送了消息" + msg + "\n");} else {//回顯自己發送的消息給自己ch.writeAndFlush("[自己]發送了消息" + msg + "\n");}});} ?@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//關閉通道ctx.close();} }客戶端
public class GroupChatClient {private final String host;private final int port; ?public GroupChatClient(String host, int port) {this.host = host;this.port = port;} ?public void run() throws Exception {EventLoopGroup group = new NioEventLoopGroup(); ?try {Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() { ?@Overrideprotected void initChannel(SocketChannel ch) throws Exception { ?//得到pipelineChannelPipeline pipeline = ch.pipeline();//加入相關handlerpipeline.addLast("decoder", new StringDecoder());pipeline.addLast("encoder", new StringEncoder());//加入自定義的handlerpipeline.addLast(new GroupChatClientHandler());}}); ?ChannelFuture channelFuture = bootstrap.connect(host, port).sync();//得到channelChannel channel = channelFuture.channel();System.out.println("-------" + channel.localAddress() + "--------");//客戶端需要輸入信息,創建一個掃描器Scanner scanner = new Scanner(System.in);while (scanner.hasNextLine()) {String msg = scanner.nextLine();//通過channel 發送到服務器端channel.writeAndFlush(msg + "\r\n");}} finally {group.shutdownGracefully();}} ?public static void main(String[] args) throws Exception {new GroupChatClient("127.0.0.1", 7000).run();} }客戶端業務處理類
public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {System.out.println(msg.trim());} }演示效果
啟動1個server端,開啟3個client端,互相聊天,記錄如下:
server
netty 服務器啟動 /127.0.0.1:55072 上線了~ /127.0.0.1:55076 上線了~ /127.0.0.1:55080 上線了~ /127.0.0.1:55072 離線了~ channelGroup size2 /127.0.0.1:55076 離線了~ channelGroup size1 /127.0.0.1:55080 離線了~ channelGroup size0client1
-------/127.0.0.1:55072-------- [客戶端]/127.0.0.1:55076 加入聊天2019-12-13 18:22:43 [客戶端]/127.0.0.1:55080 加入聊天2019-12-13 18:22:46 大家好 [自己]發送了消息大家好 [客戶]/127.0.0.1:55076 發送了消息你吃了嗎 我要走了,88 [自己]發送了消息我要走了,88 ? Process finished with exit code 130 (interrupted by signal 2: SIGINT) ?client2
-------/127.0.0.1:55076-------- [客戶端]/127.0.0.1:55080 加入聊天2019-12-13 18:22:46 [客戶]/127.0.0.1:55072 發送了消息大家好 你吃了嗎 [自己]發送了消息你吃了嗎 [客戶]/127.0.0.1:55072 發送了消息我要走了,88 [客戶端]/127.0.0.1:55072 離開了 我也要走了 [自己]發送了消息我也要走了 ? Process finished with exit code 130 (interrupted by signal 2: SIGINT)client3
-------/127.0.0.1:55080-------- [客戶]/127.0.0.1:55072 發送了消息大家好 [客戶]/127.0.0.1:55076 發送了消息你吃了嗎 [客戶]/127.0.0.1:55072 發送了消息我要走了,88 [客戶端]/127.0.0.1:55072 離開了 [客戶]/127.0.0.1:55076 發送了消息我也要走了 [客戶端]/127.0.0.1:55076 離開了 沒人了,沒意思啊,我也走了 [自己]發送了消息沒人了,沒意思啊,我也走了 ? Process finished with exit code 130 (interrupted by signal 2: SIGINT)總結
以上是生活随笔為你收集整理的Netty之实现一个简单的群聊系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java NIO模型和三大核心原理
- 下一篇: Netty之十大核心模块组件介绍