Netty应用实例-群聊系统
1.服务器端
import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; 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群聊系统服务器端 public class GroupChatServer { private int port; public GroupChatServer(int port) { this.port = port; } public void run() throws InterruptedException { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //netty启动项 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup). 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(); //解码器 pipeline.addLast("Decoder", new StringDecoder()); //编码器 pipeline.addLast("Encoder", new StringEncoder()); //添加自定义处理类 pipeline.addLast("GroupChatServerHandler",new GroupChatServerHandler()); } }); System.out.println("服务器启动了...."); ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); channelFuture.channel().closeFuture().sync(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new GroupChatServer(7777).run(); } }
2. 服务器端处理类
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()方法一加入立即执行 *方法在客户端显示 * @param ctx */ @Override public 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); } /** * channel断开后,处理方法 *在客户端显示 * @param ctx */ @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel(); channelGroup.writeAndFlush("[客户端]" + channel.remoteAddress() + " 离开了\n"); System.out.println("channelGroup size" + channelGroup.size()); } /** * 消息转发 *在客户端显示 * @param ctx * @param msg * @throws Exception */ @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { Channel channel = ctx.channel(); channelGroup.forEach(ch -> { if (channel != ch) {//将自己排除在外 ch.writeAndFlush("[客户]" + channel.remoteAddress() + "发送来消息:" + msg + "\n"); } }); } /** * channel处于活跃状态 *方法只在服务端显示 * @param ctx */ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 上线了~"); } /** * channel处于不活跃状态 *在服务端显示 * @param ctx */ @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().remoteAddress() + " 离线了~"); } /** * 异常处理 * * @param cause */ @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { //关闭通道 ctx.close(); } }
3.客户端
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 hostname; private final int port; public GroupChatClient(String hostname, int port) { this.hostname = hostname; this.port = port; } public void run() throws InterruptedException { EventLoopGroup group = new NioEventLoopGroup(); try { //客户端启动项 Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).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()); } }); //启动客户端去连接服务器端 ChannelFuture channelFuture = bootstrap.connect(hostname, port).sync(); //得到channel Channel channel = channelFuture.channel(); System.out.println("-------" + channel.localAddress() + "-------"); //客户输入信息 Scanner sc = new Scanner(System.in); while (sc.hasNextLine()) { String msg = sc.nextLine(); channel.writeAndFlush(msg + "\r\n"); } } finally { group.shutdownGracefully(); } } public static void main(String[] args) throws InterruptedException { new GroupChatClient("127.0.0.1", 7777).run(); } }
4.客户端处理类
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; public class GroupChatClientHandler extends SimpleChannelInboundHandler<String>{ @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { //输出去除两端空格的字符串 System.out.println(msg.trim()); } }