需求
1给所有在线用户推送某人上线信息
2客户端 上线、下线、离开通知服务器
3发送消息的时候,自己不接收。推送给其他客户端
4服务端获取客户端消息
代码实现
服务端处理器
public class ChartNettyServerHandler extends SimpleChannelInboundHandler<String> {
//定义一个channle 组,管理所有的channel
//GlobalEventExecutor.INSTANCE) 是全局的事件执行器,是一个单例
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
Channel channel1 = channelHandlerContext.channel();
for (Channel channel : channelGroup) {
if (Objects.equals(channel, channel1)) {
System.out.println("获取客户端消息为:"+s);
System.out.println("消息已推送给其他客户端"+">>>>>>"+channel1.remoteAddress());
} else {
channel.writeAndFlush(">>>>>"+channel1.remoteAddress()+"发送过来的消息为::::"+s);
}
}
}
//表示channel 处于活动状态, 提示 上线
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("---------------"+ctx.channel().remoteAddress()+"--------------------"+"上线!开始聊天吧!");
}
//表示channel 处于不活动状态, 提示 离线了
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("---------------"+ctx.channel().remoteAddress()+"--------------------"+"离线!");
}
/**
* C、S端一单建立Channel连接,就会触发该方法
* @param ctx
* @throws Exception
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
// 给其他客户端发送某某加入群聊
Channel channel = ctx.channel();
channelGroup.writeAndFlush("客户端:》》》》" + channel.remoteAddress() + "已加入群聊系统,注意隐士安全!");
channelGroup.add(channel);
}
/**
* Channel 下线,通知其他 客户端
* @param ctx
* @throws Exception
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channelGroup.writeAndFlush("客户端:》》》》" + channel.remoteAddress() + "退出群聊系统");
System.out.println("channle组个数="+channelGroup.size());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
}
服务端
public class ChartNettyServer {
private Integer port;
public ChartNettyServer(Integer port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossEvent = new NioEventLoopGroup();
EventLoopGroup workerEvent = new NioEventLoopGroup();
try {
// 服务器端 配置参数
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossEvent,workerEvent) // 设置两个线程组
.channel(NioServerSocketChannel.class) // nio实现类通道
.option(ChannelOption.SO_BACKLOG,128) // 设置线程队列
.childHandler(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 ChartNettyServerHandler());// 向管道追加一个处理器
}
});// 给workerGroup的EventLoop对应的管道设置处理器
System.out.println("服务器端启动完成!");
ChannelFuture cf = serverBootstrap.bind(port).sync(); // 绑定端口,并且同步,生成了一个ChannelFuture对象
// 注册监听器 到 ChannelFuture。从而获取 异步回调
cf.addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
System.out.println("监听成功:::》》》》port:"+port);
}else {
System.out.println("监听失败");
}
});
cf.channel().closeFuture().sync(); // 对关闭通道进行见监听
} finally {
bossEvent.shutdownGracefully(); // 关闭
workerEvent.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
ChartNettyServer chartNettyServer = new ChartNettyServer(7000);
chartNettyServer.run();
}
}
客户端
/**
* 功能描述: 客户端
*
* @author Songxianyang
* @date 2023-06-04 18:00
*/
public class ChartNettyClient {
private Integer port;
private String ip;
public ChartNettyClient(Integer port, String ip) {
this.port = port;
this.ip = ip;
}
private void run() throws InterruptedException {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("解码器", new StringDecoder());
pipeline.addLast("编码器", new StringEncoder());
pipeline.addLast(new ChartNettyClientHandler());
}
});
System.out.println("客户端 is ok...");
ChannelFuture channelFuture = bootstrap.connect(ip, port).sync();
Channel channel = channelFuture.channel();
System.out.println("客户端地址------"+channel.remoteAddress()+"-----");
//客户端需要创建消息
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String msg = scanner.nextLine();
//通过channel发送到服务器端
channel.writeAndFlush(msg + "\n");
}
channel.closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new ChartNettyClient(7000, "127.0.0.1").run();
}
}
客户端处理器
/**
* 功能描述:
*
* @author Songxianyang
* @date 2023-06-04 18:11
*/
public class ChartNettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println("------>"+s.trim()+"<--------");
}
}
源码地址
代码测试
客户端发送消息
其他客户端也可以收到消息