- 前言
- 一、聊天室客户端(ChatClient)
- 2.客户端自定义handler处理器
- 3.聊天室服务端(ChatServer)
- 3.服务端handler处理器
- 结果展示
前言
本人最近在学习netty,所以使用netty实现了个简易的聊天室,接下来会更新关于netty相关的内容
一、聊天室客户端(ChatClient)
public class ChatClient {
public static void main(String[] args) throws InterruptedException {
NioEventLoopGroup workGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(workGroup);
bootstrap.channel(NioSocketChannel.class);
// 设置处理器
bootstrap.handler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// 将字符串编解码器及客户端处理器添加到pipeline中
ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
ch.pipeline().addLast(new ChatClientHandler());
}
});
// 连接服务端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9000);
channelFuture.sync();
// 获取客户端输入的内容,并发送至服务端(因为添加了字符串编解码器,所以此处可以直接发送字符串)
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
channelFuture.channel().writeAndFlush(scanner.nextLine());
}
}
}
2.客户端自定义handler处理器
此处只做了基本的打印逻辑
public class ChatClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg.toString());
}
}
3.聊天室服务端(ChatServer)
public class ChatServer {
public static void main(String[] args) {
// 新建两个事件循环组,这个后续的文章会介绍
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
ch.pipeline().addLast(new ChatServerHandler());
}
});
// 服务端绑定9000端口
serverBootstrap.bind(9000);
}
}
3.服务端handler处理器
public class ChatServerHandler extends ChannelInboundHandlerAdapter {
// 创建一个list集合存储连接上的所有客户端channel
private static List channels = new ArrayList<>();
// 当有客户端连接上服务端,底层会调用此方法,执行此方法的逻辑
// 这里大概的处理逻辑是:先添加新客户端channel到集合中,然后循环遍历list集合
// 然后根据不同的channel发送不同的系统消息
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channels.add(channel);
channels.forEach(ch -> {
if (ch == channel) {
channel.writeAndFlush("恭喜您,上线成功");
} else {
ch.writeAndFlush("系统消息:[" + ch.remoteAddress() + "]客户端已上线");
}
});
System.out.println("客户端[" + channel.remoteAddress() + "]请求连接");
}
// 当有客户端连断开连接,底层会调用此方法,执行此方法的逻辑
// 这里大概的处理逻辑是:然后循环遍历list集合,找到已断开连接的channel并删除
// 向集合内的channel发送系统消息
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
Iterator iterator = channels.iterator();
while (iterator.hasNext()) {
Channel ch = iterator.next();
if (ch == channel) {
iterator.remove();
}
ch.writeAndFlush("系统消息:[" + channel.remoteAddress() + "]客户端已下线");
}
System.out.println("客户端[" + channel.remoteAddress() + "]断开连接");
}
// 当有客户端发送消息到服务端,底层会调用此方法,执行此方法的逻辑
// 这里大概的处理逻辑是:循环遍历向集合中的channel(除发送消息的客户端)发送消息
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = ctx.channel();
System.out.println("服务端收到客户端[" + channel.remoteAddress() + "]发来的消息:" + msg.toString());
String now = DateUtil.now();
channels.forEach(ch -> {
if (ch != channel) {
ch.writeAndFlush("消息时间:" + now + " 用户[" + channel.remoteAddress() + "]说:" + msg.toString());
}
});
}
}
结果展示
1.chatServer控制台输出:
2.客户端127.0.0.1:55408控制台输出
3.客户端5127.0.0.1:55422控制台输出
以上就是聊天室的基本内容了,第一次写博客,略显生疏,往后继续更新所学技术知识



