1.流程图
2.实现服务端业务1
编写基础服务端Netty代码
/**
* @author Kyle
* @date 2024/02/16
* 群聊系统服务端
*/
public class ChatServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 配置参数
serverBootstrap.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringEncoder());
pipeline.addLast(new StringDecoder());
pipeline.addLast(new ChatServerHandler());
}
});
System.out.println("聊天室服务器启动");
ChannelFuture channelFuture = serverBootstrap.bind(9090).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
3.实现服务端业务2
编写ChatServerHandler
,继承SimpleChannelInboundHandler
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 存放Channel的容器,可以执行对每个Channel进行操作的任务,任务由GlobalEventExecutor来执行
private static final ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 有新的客户端连接了,将该客户端的上线消息广播给其他的客户端
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// 得到客户端的channel
Channel channel = ctx.channel();
String message = "客户端-" + channel.remoteAddress() +"于"+sdf.format(new Date())+"上线了";
System.out.println(message);
// 向其他客户端发送该客户端的上线消息
channelGroup.writeAndFlush(message);
// 将该客户端加入到channelGroup容器中
channelGroup.add(channel);
}
/**
* 客户端下线则广播给其他客户端
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
// 生成下线的消息
String message = "客户端-" + channel.remoteAddress() +"于"+sdf.format(new Date())+"下线了";
System.out.println(message);
channelGroup.writeAndFlush(message);
}
/**
* 具体读数据的业务
* @param ctx
* @param msg
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel();
// 遍历所有的channel
channelGroup.forEach(ch -> {
if (ch != channel) {
// 发给其他客户端
ch.writeAndFlush("客户端-"+channel.remoteAddress()+"于"+sdf.format(new Date())+"说:" + msg + "\n");
} else {
// 发给当前消息的客户端
ch.writeAndFlush("我于"+sdf.format(new Date())+"说:" + msg + "\n");
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.channel().close();
}
}
4.实现客户端业务
编写客户端
public class ChatClient {
public static void main(String[] args) {
NioEventLoopGroup eventExecutors = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventExecutors)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(new ChatClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 9090).sync();
Channel channel = channelFuture.channel();
// 发送消息
System.out.println("欢迎进入聊天室");
Scanner sc = new Scanner(System.in);
while (sc.hasNextLine()) {
String msg = sc.nextLine();
channel.writeAndFlush(msg);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
eventExecutors.shutdownGracefully();
}
}
}
5.实现客户端业务2
编写ChatClientHandler
,继承SimpleChannelInboundHandler
public class ChatClientHandler extends SimpleChannelInboundHandler<String> {
/**
* 打印消息在控制台
* @param channelHandlerContext
* @param msg
* @throws Exception
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
System.out.println(msg.trim());
}
}