目录
四、ChannelManger和GroupManager实现
一、介绍
本章节主要讲第二部分,涉及服务端的实现,主要包括服务端的创建、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的实现,看以下文章: