[Netty实践] 简单聊天实现(二):server部分

目录

一、介绍

二、 结构

三、依赖

四、ChannelManger和GroupManager实现

五、 Request消息处理Handler实现

六、ServerChannelInitializer实现

七、 ChatServer实现

八、启动ChatServer

九、后续文章


一、介绍

本章节主要讲第二部分,涉及服务端的实现,主要包括服务端的创建、channel管理、组管理、对应各种Handler实现。

如果你还没有看过第一部分,那么请通过下面这篇文章进行学习:

https://blog.csdn.net/Staba/article/details/135057482

二、 结构

三、依赖

<dependencies>
        
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.101.Final</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>chat-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

四、ChannelManger和GroupManager实现

ChannelManager用于管理用户与Channel之间的绑定,此处进行管理的原因是,当用户给另外一个用户发送消息时,我们通过该manager获取到目标用户的channel进行写消息

public class ChannelManager {

    private final static Map<String, Channel> channelMap = new ConcurrentHashMap<>();

    public static void addChannel(String username, Channel channel){
        channelMap.put(username, channel);
    }

    public static Channel getChannel(String username) {
        return channelMap.get(username);
    }


}

GroupManager用于管理用户与群组之间的绑定,此处减少了工作量,直接初始化好了群组,有需求的可以自己动手实现创建群组 

public class GroupManager {

    //private final static Map<String, Map<String, ChannelGroup>> groupMap = new ConcurrentHashMap<>();
    private final static Map<String, Map<String, List<String>>> userGroupMap = new ConcurrentHashMap<>();

    static {
        Map<String, List<String>> groupMap = new HashMap<>();


        // 给001用户新增一个组,组员有002
        List<String> members1 = new ArrayList<>();
        members1.add("002");
        groupMap.put("group1", members1);

        // 给001用户新增一个组,组员有002、003
        List<String> members2 = new ArrayList<>();
        members2.add("002");
        members2.add("003");
        groupMap.put("group2", members2);

        userGroupMap.put("001", groupMap);
    }

    public static List<String> getGroupUsers(String username, String group) {
        return userGroupMap.get(username).get(group);
    }

}

五、 Request消息处理Handler实现

1、BaseHandler,所有Handler的父类

public abstract class BaseHandler<T> extends SimpleChannelInboundHandler<T> {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端进行连接, channel: " + ctx.channel());
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端断开连接, channel: " + ctx.channel());
        super.channelInactive(ctx);
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("出现异常断开, channel: " + ctx.channel());
        cause.printStackTrace();
        // todo, 清除相关数据
    }
}

2、LoginRequestHandler,用于处理用户登录请求

public class LoginRequestHandler extends BaseHandler<LoginRequest> {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginRequest msg) throws Exception {
        System.out.println("[LoginRequestHandler]读取到客户端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);

        // 假设登录成功了
        ChannelManager.addChannel(msg.getUsername(), ctx.channel());

        LoginResponse loginResponse = new LoginResponse(true, "登录成功!");
        ctx.channel().writeAndFlush(loginResponse);
    }

}

3、SingleMessageRequestHandler,用于处理用户私聊请求

public class SingleMessageRequestHandler extends BaseHandler<SingleMessageRequest> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, SingleMessageRequest msg) throws Exception {
        System.out.println("[SingleMessageRequestHandler]读取到客户端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);

        // 向目标用户发送
        Channel targetChannel = ChannelManager.getChannel(msg.getSendTo());

        SingleMessageResponse singleMessageResponse = new SingleMessageResponse(msg.getSendFrom(), msg.getContent());

        targetChannel.writeAndFlush(singleMessageResponse);
    }

}

4、GroupMessageRequestHandler,用于处理用户发送群消息请求

public class GroupMessageRequestHandler extends BaseHandler<GroupMessageRequest> {


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, GroupMessageRequest msg) throws Exception {
        System.out.println("[GroupMessageRequestHandler]读取到客户端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);

        List<String> users = GroupManager.getGroupUsers(msg.getSendFrom(), msg.getGroup());

        for (String user : users) {
            Channel channel = ChannelManager.getChannel(user);

            GroupMessageResponse groupMessageResponse = new GroupMessageResponse(msg.getSendFrom(), msg.getGroup(), msg.getContent());

            channel.writeAndFlush(groupMessageResponse);
        }

    }

}

六、ServerChannelInitializer实现

该类用于初始化Server与Client通信的Channel,需要将我们前面写的编解码器以及RequestHandler添加进pipeline

public class ServerChannelInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();

        pipeline.addLast(new MessageEncode());
        pipeline.addLast(new MessageDecode());

        pipeline.addLast(new LoginRequestHandler());
        pipeline.addLast(new SingleMessageRequestHandler());
        pipeline.addLast(new GroupMessageRequestHandler());
    }

}

七、 ChatServer实现

public class CharServer {

    public void bind(Integer port) {
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        EventLoopGroup chileGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(parentGroup, chileGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ServerChannelInitializer());

            // 阻塞,等待建立成功
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();

            System.out.println("chatServer 启动成功...");

            // 阻塞,等待关闭
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            chileGroup.shutdownGracefully();
            parentGroup.shutdownGracefully();
        }
    }

}

八、启动ChatServer

public class ChatServerTest {

    public static void main(String[] args) {
        new CharServer().bind(8888);
    }

}

看到控制台打印,启动成功

chatServer 启动成功...

九、后续文章

 以上就是本节需要实现的所有内容,接下来关于client的实现,看以下文章:

https://blog.csdn.net/Staba/article/details/135061661

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值