Netty实现简单的多人聊天

1、服务端代码:服务端配置、服务端自定义事件处理类。
自定义事件处理类 – NettyServerHandler :

  • 继承类SimpleChannelInboundHandler,使用泛型,此处泛型的数据类型和接收的消息的数据类型一致
  • 此类默认自动将接收到的消息转换成此类型数据

public class NettyServerHandler extends SimpleChannelInboundHandler<String> {

    /**
     * 注:此方法需设置成静态
     */
    public static List<Channel> channelList = new ArrayList<>();

    /**
     * 通道就绪事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       //获取就绪通道
        Channel channel = ctx.channel();   //获取当前准备就绪通道
        channelList.add(channel);  //新增准备就绪通道
        //获取通道的地址,转换成String类型,从下表为1的位置截取该字符串
        System.out.println("[Server:"+channel.remoteAddress().toString().substring(1)+"] 上线!");
    }

    /**
     * 通道未就绪事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();  //获取当前为准备就绪通道
        channelList.remove(channel);   //移除当前未就绪通道
        System.out.println("[Server:"+channel.remoteAddress().toString().substring(1)+"] 下线!");
    }

    /**
     * 数据读取时间
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        Channel channel = ctx.channel(); //获取当前接发送消息的通道
        //广播接收到的消息给除了当前通道对应客户端的其他通道客户端
        for (Channel ch : channelList) { //遍历所有在线的通道
            if (ch != channel){  //排除当前通道
                ch.writeAndFlush("用户"+channel.remoteAddress().toString().substring(1)+"说:"+msg);
            }
        }
    }

    /**
     * 异常处理事件
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("通道"+ctx.channel().remoteAddress().toString().substring(1)+"捕获到异常!");
    }
}

服务端配置类 – NettyServer

public class NettyServer {
    public static void main(String[] args) {
        new NettyServer(8888).run();
    }

    private int port;
    public NettyServer(int port){
        this.port = port;
    }

    public void run(){
        //网络连接线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //IO操作线程组
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            //服务端启动助手
            ServerBootstrap bs = new ServerBootstrap();
            bs.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class) //服务端通道的实现
                    .option(ChannelOption.SO_BACKLOG,512)   //通道中允许连接等待的数量
                    .childOption(ChannelOption.SO_KEEPALIVE,true)  //保持连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {//自定义通道事件处理类初始化,往链中添加自定义的事件处理类
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline cpp = ch.pipeline();  //获取链
                            //解码
                            cpp.addLast("decoder",new StringDecoder());
                            //编码
                            cpp.addLast("encoder",new StringEncoder());
                            //添加自定义事件处理类,此处需要注意:自定义的事件处理类要在编解码配置后
                            cpp.addLast("handler",new NettyServerHandler());
                        }
                    });
            //绑定服务端端口
            ChannelFuture bf = bs.bind(port).sync();
            System.out.println(".........服务端启动成功.........");

            //关闭通道
            bf.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

2、客户端代码:客户端配置类、客户端自定义事件处理类
**客户端自定义事件处理类 – NettyClientHandler **

public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
    /**
     * 数据读取事件
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(msg.trim());
    }
}

客户端配置类 – NettyCient :


public class NettyCient {
    public static void main(String[] args) {
        new NettyCient("127.0.0.1",8888).run();
    }

    private String ipAddress;
    private int port;
    public NettyCient(String ipAddress,int port){
        this.ipAddress = ipAddress;
        this.port = port;
    }

    public void run(){
        //客户端线程组
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            //客户端启动助手
            Bootstrap b = new Bootstrap();

            b.group(group)
                    .channel(NioSocketChannel.class)  //客户端通道实现类
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline cpp = ch.pipeline();
                            cpp.addLast("decoder",new StringDecoder());
                            cpp.addLast("encoder",new StringEncoder());
                            cpp.addLast("handler",new NettyClientHandler());
                        }
                    });
            //连接服务端
            ChannelFuture cf = b.connect(ipAddress,port).sync();
            System.out.println("---------客户端启动成功--------");
            //java控制台输入
            Scanner sc = new Scanner(System.in);
            while(sc.hasNextLine()){
                String str = sc.nextLine();
                cf.channel().writeAndFlush(str+"\n");  //将控制台输入的值写入通道
            }
            //通道关闭
            cf.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值