Netty 实现TCP群聊系统

好久没写博客了,2020第一篇博客!

  • Netty 我这边就不多加说明了,同步非阻塞典型的NIO架构
  • 不过Netty在原有的NIO基础上进行了封装,操作更加简便。
  • Selector Channel Buffer 这些组件概念我也不去啰嗦。
  • 单Selector 单线程,单Selector多线程,主从Selector多线程 为什么说这一点,因为Netty就是根据主从Selector多线程演变过来的。

我上面这些 这些关键字我这边不做阐述,怕啰嗦…

上代码

  • Netty 服务器端
/**
 *
 *  基于Netty 实现 http 服务器
 */
public class NettyChatServer {


    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup  = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();


            serverBootstrap
                    .group(bossGroup,workerGroup)
                    //设置线程连接个数
                    .option(ChannelOption.SO_BACKLOG,128)
                    .channel(NioServerSocketChannel.class)
                    // 连接处于活动状态
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new NettyChatInitializer());
            ChannelFuture channelFuture = serverBootstrap.bind(6863).sync();

            //添加监听器
            channelFuture.addListener(future -> {
                if (channelFuture.isSuccess()) {
                    System.out.println("服务器启动成功!连接为:tcp://"+channelFuture.channel().localAddress());
                }

            });

            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();

        }

    }

  • 服务器端Handler
public class NettyChatInitializer extends ChannelInitializer<SocketChannel> {
    //存储该 初始化Channel 用余每次发送群聊消息
    public static final List<SocketChannel> socketChannels = new LinkedList<>();

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        // ch 类型是 NioSocketChannel
        socketChannels.add(ch);
        ch.pipeline().addLast(new NettyChatHandler());


    }


  • Netty服务器端Handler
public class NettyChatHandler extends SimpleChannelInboundHandler<Object> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //System.out.println("客户端消息为:"+((ByteBuf) msg).toString(CharsetUtil.UTF_8));
        String mesStr = ((ByteBuf) msg).toString(CharsetUtil.UTF_8);
        // 进行群发路由 这个 channel 就是 NioSocketChannel
        Channel channel = ctx.channel();
        NettyChatInitializer.socketChannels.forEach(socketChannel -> {
            if ( socketChannel instanceof Channel && socketChannel != channel){
                socketChannel.writeAndFlush(Unpooled.copiedBuffer(channel.remoteAddress()+": "+mesStr,CharsetUtil.UTF_8));
            }
        });
       /* ByteBuf byteBuf = Unpooled.copiedBuffer("我知道了 我是服务器", CharsetUtil.UTF_8);
        ctx.writeAndFlush(byteBuf);*/
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        NettyChatInitializer.socketChannels.remove(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println("异常产生:"+cause.getMessage());
        NettyChatInitializer.socketChannels.remove(ctx.channel());
        ctx.close();
    }

  • 客户端
public class NettyChatClient {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup clientGroups = new NioEventLoopGroup(1);

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(clientGroups)
                       .channel(NioSocketChannel.class)
                        .handler(new NettyChatClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6863).sync();

            channelFuture.addListener(future -> {
                if (future.isSuccess()) {
                    System.out.println("客户端启动成功 " + channelFuture.channel().localAddress());
                }


            });

            channelFuture.channel().closeFuture().sync();

        }finally {
            clientGroups.shutdownGracefully();
        }
    }

}

  • 客户端Handler
public class NettyChatClientInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ch.pipeline().addLast(new NettyChatClientHandler());


    }

  • 客户端Handler
public class NettyChatClientHandler extends SimpleChannelInboundHandler<Object> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println(((ByteBuf) msg).toString(CharsetUtil.UTF_8));

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf byteBuf = Unpooled.copiedBuffer("我知道了1", CharsetUtil.UTF_8);
        ctx.writeAndFlush(byteBuf);
        new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNextLine()) {
                ctx.writeAndFlush(Unpooled.copiedBuffer(scanner.nextLine(),CharsetUtil.UTF_8));
            }
        }).start();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println("异常产生:"+cause.getMessage());
        ctx.close();
    }

说明:

  1. 以上代码就是基于Netty的TCP网络编程的范本,学习Netty可以用来参考。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值