netty5.0 群聊demo


服务端 启动及配置

package com.lq.designpatterns.netty.groupchat;


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;

/**
 * @ClassName:GroupChatServer
 * @Descraption: 群聊服务端
 **/
public class GroupChatServer {
    private int port;

    public GroupChatServer(int port){
        this.port=port;
    }

    public void run() throws InterruptedException {
        // 创建两个线程组
        // 设置线程组中线程的个数为1,默认是8个
        EventLoopGroup bossGroup=new NioEventLoopGroup(1);
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try{
        ServerBootstrap b=new ServerBootstrap();
        b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG,128)
                .childOption(ChannelOption.SO_KEEPALIVE,true)
                .childHandler(new ChannelInitializer() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        // 加入解码器
                        pipeline.addLast("decoder",new StringDecoder());
                        // 加入编码器
                        pipeline.addLast("encoder", new StringEncoder());
                        // 加入自己的业务处理handler
                        pipeline.addLast(new GroupChatServerHandler());
                    }
                });
        System.out.println("netty 服务器启动");
        ChannelFuture sync = b.bind(port).sync();
        // 监听关闭
        sync.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new GroupChatServer(7000).run();
    }
}

服务端处理器

package com.lq.designpatterns.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.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * @ClassName:GroupChatServerHandler
 * @Descraption: 服务端处理器
 **/
public class GroupChatServerHandler extends SimpleChannelInboundHandler {

    /**
     * 定义一个channel组,管理所有的channel
     * GlobalEventExecutor.INSTANCE 是全局的事件处理器,是一个单例
     */
    private static ChannelGroup channelGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    /** 时间格式化 */
    private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("HH:mm:ss");

    /**
     *  handlerAdded 表示连接建立,一旦连接建立,第一个被执行
     *  将当前channel加入到 channelGroup
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 将该客户加入聊天的信息推送给其他在线的客户端
        // 该方法会将channelGroup中所有的channel遍历,并发送消息,无需手动遍历
        channelGroup.writeAndFlush(DTF.format(LocalTime.now())+" [客户端]****"+channel.remoteAddress()+"****加入聊天群\n");
        channelGroup.add(channel);
    }
    /**
     * 断开连接会被触发,将xx客户离开推送给所有人
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        // 将该客户离开聊天的信息推送给其他在线的客户端
        // 该方法会将channelGroup中所有的channel遍历,并发送消息,无需手动遍历
        // 离开的时候会自动在channelGroup移除
        channelGroup.writeAndFlush(DTF.format(LocalTime.now())+" [客户端]****"+channel.remoteAddress()+"****离开聊天群\n");
    }

    /**
     * 表示channel 处理活动状态,提示 xx 上线
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(DTF.format(LocalTime.now())+" "+ctx.channel().remoteAddress()+"····上线了");
    }

    /**
     * 表示channel 处理非活动状态,提示 xx 离线
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(DTF.format(LocalTime.now())+" "+ctx.channel().remoteAddress()+"····下线了");
    }

    /**服务端读取数据*/
    @Override
    protected void messageReceived(ChannelHandlerContext ctx, String s) throws Exception {
        // 获取到当前channel
        Channel channel = ctx.channel();
        // 这是我们遍历channelGroup,根据不同的情况发送不同的信息
        channelGroup.forEach(ch->{
            if(channel!=ch){
                ch.writeAndFlush(DTF.format(LocalTime.now())+" "+"[客户] "+channel.remoteAddress()+" 发送消息"+s+"\n");
            }else {
                ch.writeAndFlush(DTF.format(LocalTime.now())+" "+"[自己发送了消息]:"+s+"\n");
            }
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 发生异常关闭通道
        ctx.close();
    }

}

客户端启动及配置

package com.lq.designpatterns.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;

/**
 * @ClassName:CroupChatCllient
 * @Descraption: 群聊客户端
 **/
public class CroupChatClient {
    private final String host;
    private final int port;

    public CroupChatClient(String host,int port){
        this.host=host;
        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() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 加入解码器
                            pipeline.addLast("decoder", new StringDecoder());
                            // 加入编码器
                            pipeline.addLast("encoder", new StringEncoder());
                            // 加入自己的业务处理handler
                            pipeline.addLast(new GroupChatClientHandler());
                        }
                    });
            ChannelFuture channelFuture = bootstrap.connect(host, 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 CroupChatClient("localhost",7000).run();
    }
}

客户端处理器


package com.lq.designpatterns.netty.groupchat;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * @ClassName:GroupChatClientHandler
 * @Descraption: 客户端处理
 **/
public class GroupChatClientHandler extends SimpleChannelInboundHandler {
    @Override
    protected void messageReceived(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
        System.out.println(s.trim());
    }
}

 

你可能感兴趣的:(netty5.0 群聊demo)