• Netty聊天实现


     

     <dependency>
         <groupId>io.netty</groupId>
         <artifactId>netty-all</artifactId>
         <version>4.1.42.Final</version>
    </dependency>
    public class NettyServer {
        public static void main(String[] args) throws Exception {
            //创建两个线程组bossGroup和workerGroup, 含有的子线程NioEventLoop的个数默认为cpu核数的两倍
            // bossGroup只是处理连接请求 ,真正的和客户端业务处理,会交给workerGroup完成
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                //创建服务器端的启动对象
                ServerBootstrap bootstrap = new ServerBootstrap();
                //使用链式编程来配置参数
                bootstrap.group(bossGroup, workerGroup) //设置两个线程组
                        .channel(NioServerSocketChannel.class) //使用NioServerSocketChannel作为服务器的通道实现
                        // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接。
                        // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
                        .option(ChannelOption.SO_BACKLOG, 1024)
                        .childHandler(new ChannelInitializer<SocketChannel>() {//创建通道初始化对象,设置初始化参数
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast("decoder",new StringDecoder());
                                ch.pipeline().addLast("encoder",new StringEncoder());
                                //对workerGroup的SocketChannel设置处理器
                                ch.pipeline().addLast(new NettyServerHandler());
    
                            }
                        });
                System.out.println("聊天室启动成功。。");
                //绑定一个端口并且同步, 生成了一个ChannelFuture异步对象,通过isDone()等方法可以判断异步事件的执行情况
                //启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕
                ChannelFuture cf = bootstrap.bind(9000).sync();
    
                //对通道关闭进行监听,closeFuture是异步操作,监听通道关闭
                //通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
                cf.channel().closeFuture().sync();
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
    
        //存储所有连接的channel
        private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        // 表示channel 处于就绪状态,提示上线
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws  Exception{
            Channel channel = ctx.channel();
            channelGroup.writeAndFlush("[客户端]"+channel.remoteAddress()+"上线了"+ sdf.format(new java.util.Date()));
            channelGroup.add(channel);
            System.out.println(ctx.channel().remoteAddress()+"上线了");
            System.out.println("在线人数:"+channelGroup.size());
        }
        //表示channel处于不活动状态,提示离线了
        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            Channel channel =ctx.channel();
            //将客户离开信息推送给当前在线用户
            channelGroup.writeAndFlush("【客户端】"+channel.remoteAddress()+"离线了
    ");
            System.out.println(ctx.channel().remoteAddress()+"下线了");
            System.out.println("在线人数:"+channelGroup.size());
        }
    
        /**
         * 读取客户端发送的数据
         *
         * @param ctx 上下文对象, 含有通道channel,管道pipeline
         * @param s 就是客户端发送的数据
         * @throws Exception
         */
        protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
            final Channel channel = ctx.channel();
            channelGroup.forEach(ch->{
                if(channel!=ch){
                    ch.writeAndFlush("【客户端】"+channel.remoteAddress()+"发送消息:"+s+"
    ");
                }else{
                    ch.writeAndFlush("【自己】发送了消息:"+s+"
    ");
                }
            });
        }
        /** * 处理异常, 一般是需要关闭通道
         *  * 89 * @param ctx
         *  * @param cause
         *  * @throws Exception
         *  */
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    public class NettyClient {
        public static void main(String[] args) throws Exception {
            //客户端需要一个事件循环组
            EventLoopGroup group = new NioEventLoopGroup();
            try {
                //创建客户端启动对象
                //注意客户端使用的不是 ServerBootstrap 而是 Bootstrap
                Bootstrap bootstrap = new Bootstrap();
                //设置相关参数
                bootstrap.group(group) //设置线程组
                        .channel(NioSocketChannel.class) // 使用 NioSocketChannel 作为客户端的通道实现
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel channel) throws Exception {
                                channel.pipeline().addLast(new StringDecoder());
                                channel.pipeline().addLast(new StringEncoder());
                                //加入处理器
                                channel.pipeline().addLast(new NettyClientHandler());
                            }
                        });
                //启动客户端去连接服务器端
                ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000).sync();
                Channel channel = channelFuture.channel();
                System.out.println("客户端启动成功:" + channel.localAddress() ) ;
                Scanner scanner =new Scanner(System.in);
                while (scanner.hasNextLine()){
                    String msg = scanner.nextLine();
                    channel.writeAndFlush(msg);
                }
                //对关闭通道进行监听
                channelFuture.channel().closeFuture().sync();
            } finally {
                group.shutdownGracefully();
            }
        }
    }
    public class NettyClientHandler extends SimpleChannelInboundHandler<String>{
    
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
            System.out.println(s.trim());
        }
    }
  • 相关阅读:
    使用工具自动生成Linq类文件
    DateTime.MinValue和MaxValue引发的异常
    C# AD 验证登陆
    HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法
    清理sqlserver 2012 日志文件
    如何修改博客园插入代码的默认代码大小?
    hdu 1241:Oil Deposits(DFS)
    【2014年寒假日常记录表(2014.1.9—2.23,45天)】
    hdu 1016 Prime Ring Problem(DFS)
    蓝桥杯 历届试题 错误票据(水题,排序)
  • 原文地址:https://www.cnblogs.com/liaoyd/p/14292014.html
Copyright © 2020-2023  润新知