一、基於netty羣聊
服務器端
package com.github.bjlhx15.netty.demo.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; import java.text.SimpleDateFormat; public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> { //定義一個channel組。管理所有的channel //GlobalEventExecutor.INSTANCE是全局的事件執行器,是一個單例 private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //handlerAdded 表示連接建立,一旦連接,第一個被執行 // 當前的channel加入到 channelgroup @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); // 將該客戶加入聊天的信息推送到其他所有客戶端 // 該方法會將 channelGroup中所有的channel遍歷,併發送消息,不需要自己遍歷 channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 加入聊天\n"); channelGroup.add(channel); } //斷開連接 @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 離開了\n"); // channelGroup.remove()//不需要執行這裏,這個方法會觸發channelGroup 刪除這個channel } // 表示channel處於活動狀態 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 上線了"); } // 表示channel處於不活動狀態 @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 離線了"); } @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { // 獲取到當前的channel Channel channel = channelHandlerContext.channel(); channelGroup.forEach(ch -> { if (channel != ch) { ch.writeAndFlush("[客戶]" + channel.remoteAddress() + " 發送消息," + s + "\n"); } else { ch.writeAndFlush("[自己]發送了消息" + s + "\n"); } }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
服務器端Handler
package com.github.bjlhx15.netty.demo.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; import java.text.SimpleDateFormat; public class GroupChatServerHandler extends SimpleChannelInboundHandler<String> { //定義一個channel組。管理所有的channel //GlobalEventExecutor.INSTANCE是全局的事件執行器,是一個單例 private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //handlerAdded 表示連接建立,一旦連接,第一個被執行 // 當前的channel加入到 channelgroup @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); // 將該客戶加入聊天的信息推送到其他所有客戶端 // 該方法會將 channelGroup中所有的channel遍歷,併發送消息,不需要自己遍歷 channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 加入聊天\n"); channelGroup.add(channel); } //斷開連接 @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); channelGroup.writeAndFlush("[客戶端]" + channel.remoteAddress() + " 離開了\n"); // channelGroup.remove()//不需要執行這裏,這個方法會觸發channelGroup 刪除這個channel } // 表示channel處於活動狀態 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 上線了"); } // 表示channel處於不活動狀態 @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 離線了"); } @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { // 獲取到當前的channel Channel channel = channelHandlerContext.channel(); channelGroup.forEach(ch -> { if (channel != ch) { ch.writeAndFlush("[客戶]" + channel.remoteAddress() + " 發送消息," + s + "\n"); } else { ch.writeAndFlush("[自己]發送了消息" + s + "\n"); } }); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } }
客戶端
package com.github.bjlhx15.netty.demo.netty.groupchat; 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.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import java.util.Scanner; 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 InterruptedException { EventLoopGroup eventExecutors = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap() .group(eventExecutors) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast("decoder", new StringDecoder()); pipeline.addLast("encoder", new StringEncoder()); pipeline.addLast(new GroupChatClientHandler());//加入自己業務的handler } }); ChannelFuture channelFuture = bootstrap.connect(host, port).sync(); Channel channel = channelFuture.channel(); System.out.println("------------" + channel.localAddress() + "-------"); Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()) { String s = scanner.nextLine(); channel.writeAndFlush(s + "\r\n"); } } finally { eventExecutors.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new GroupChatClient("127.0.0.1", 7000).run(); } }
客戶端Handler
package com.github.bjlhx15.netty.demo.netty.groupchat; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; public class GroupChatClientHandler extends SimpleChannelInboundHandler<String> { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { System.out.println(s.trim()); } }
啓動測試即可
如果有私聊,需要將ChannelGroup ,替換爲Map<String,Channel>,key是用戶ID,然後就能找到對應的Channel,在ChannelRead0時查找發送即可。