在Netty中提供了ChannelGroup接口,该接口继承Set接口,因此可以通过ChannelGroup可管理服务器端所有的连接的Channel,然后对所有的连接Channel广播消息。

Server端:

public class BroadCastServer {

    public static void run(int port) {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker)
.channel(NioServerSocketChannel.class) // 设置Channel Type
.option(ChannelOption.SO_BACKLOG, 1024) // 设置Channel属性
.childHandler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new BroadCastChannelHandler());
}
});
ChannelFuture channelFuture = bootstrap.bind(port).sync();
if (channelFuture.isDone()) {
System.out.println(String.format("server bind port %s sucess", port));
}
Channel channel = channelFuture.channel();
/**CloseFuture异步方式关闭*/
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
} public static void main(String []args) {
BroadCastServer.run(8080);
} } public class BroadCastChannelHandler extends ChannelInboundHandlerAdapter { private static final Gson GSON = new GsonBuilder().create(); private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static final AtomicInteger response = new AtomicInteger(); @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel ch = ctx.channel();
if (ChannelGroups.size() > 0) {
Message msg = new Message(ch.remoteAddress().toString().substring(1), SDF.format(new Date()));
ChannelGroups.broadcast(GSON.toJson(msg), new ChannelMatchers());
}
ChannelGroups.add(ch);
} @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (ChannelGroups.contains(ch) && String.valueOf(msg).equals("welcome")) {
System.out.println(String.format("receive [%s] from [%s] at [%s]", String.valueOf(msg) ,
ch.remoteAddress().toString().substring(1), SDF.format(new Date())));
response.incrementAndGet();
}
synchronized (response) {
System.out.println(response.get() + "\t" + ChannelGroups.size());
if (response.get() == ChannelGroups.size() - 1) {
System.out.println("server close all connected channel");
ChannelGroups.disconnect();
response.set(0);
}
}
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} @Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
ctx.close();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ChannelGroups.discard(ctx.channel());
response.decrementAndGet();
} public static class ChannelMatchers implements ChannelMatcher { @Override
public boolean matches(Channel channel) {
return true;
} } }

服务器端收到所有连接客户端对广播消息的响应后,服务器端主动关闭已连接的Channel

客户端:

public class Client	{

	private static final String host = "127.0.0.1";

	private static final int port = 8080;

	private static final ExecutorService es = Executors.newFixedThreadPool(5);

	public static void start() {
for (int i = 0; i < 5; i++) {
es.execute(new Task());
}
es.shutdown();
} public static class Task implements Runnable { @Override
public void run() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new SimpleClientChannelHandler());
} });
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
if (channelFuture.isSuccess()) {
System.out.println(String.format("connect server(%s:%s) sucess", host, port));
}
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
} } public static void main(String []args) {
Client.start();
}
} public class SimpleClientChannelHandler extends ChannelInboundHandlerAdapter { @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = ctx.channel();
System.out.println(String.format("client(%s) receive message [%s]", channel.localAddress().toString().substring(1),
String.valueOf(msg)));
System.out.println();
ctx.writeAndFlush(String.valueOf("welcome"));
} @Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
ctx.disconnect(ctx.newPromise());
ctx.close();
System.out.println(String.format("client(%s) close sucess", ctx.channel().localAddress().toString().substring(1)));
}
}

  本文使用ChannelGroups辅助类管理服务器端已连接的Channel,代码实现如下:

public class ChannelGroups {

    private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup("ChannelGroups", GlobalEventExecutor.INSTANCE);

    public static void add(Channel channel) {
CHANNEL_GROUP.add(channel);
} public static ChannelGroupFuture broadcast(Object msg) {
return CHANNEL_GROUP.writeAndFlush(msg);
} public static ChannelGroupFuture broadcast(Object msg, ChannelMatcher matcher) {
return CHANNEL_GROUP.writeAndFlush(msg, matcher);
} public static ChannelGroup flush() {
return CHANNEL_GROUP.flush();
} public static boolean discard(Channel channel) {
return CHANNEL_GROUP.remove(channel);
} public static ChannelGroupFuture disconnect() {
return CHANNEL_GROUP.disconnect();
} public static ChannelGroupFuture disconnect(ChannelMatcher matcher) {
return CHANNEL_GROUP.disconnect(matcher);
} public static boolean contains(Channel channel) {
return CHANNEL_GROUP.contains(channel);
} public static int size() {
return CHANNEL_GROUP.size();
}
}

  

Netty利用ChannelGroup广播消息的更多相关文章

  1. rabbitMQ应用,laravel生产广播消息,springboot消费消息

    最近做一个新需求,用户发布了动态,前台需要查询,为了用户读取信息响应速度更快(MySQL很难实现或者说实现起来很慢),所以在用户动态发布成功后,利用消息机制异步构建 redis缓存 和 elastic ...

  2. node的socket.io的广播消息

    在多个客户端与服务器端建立连接后,socket.io()服务器具有一个sockets属性,属性值为所有与客户端建立连接的socket对象.可以利用该对象的send方法或emit方法向所有客户端广播消息 ...

  3. Linux下UDP收/发广播消息简单实现

    发送广播消息 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/typ ...

  4. Linux系统下UDP发送和接收广播消息小例子

    // 发送端 #include <iostream> #include <stdio.h> #include <sys/socket.h> #include < ...

  5. 利用System V消息队列实现回射客户/服务器

    一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...

  6. 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了

    系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...

  7. Android中利用Handler实现消息的分发机制(三)

    在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...

  8. 利用rabbit_mq队列消息实现对一组主机进行命令下发

    目的: 利用rabbit_mq队列消息实现对一组主机进行命令下发 server: #!/usr/bin/env python3.5 # -*- coding:utf8 -*- import os,sy ...

  9. Openfire开发广播服务接口,支持离线广播消息

    Openfire开发广播服务接口,支持离线广播消息 概要 最近公司要求做一个web端向所有移动端发送公告,所以考虑到即时性就用openfire做服务.不过为了减轻web端的工作量,我们开发一个简单的插 ...

随机推荐

  1. CentOS7安装和配置rsync+inotify

    (1)rsync介绍 1.rsync介绍 开源,实现全量及增量的本地或远程数据同步备份工具 2.工作场景: 存储实时备份:rsync+inotify 定时备份:rsync+crond 3.rsync工 ...

  2. Bootstrap Table 使用示例及代码

    http://issues.wenzhixin.net.cn/bootstrap-table/ <!DOCTYPE html> <html> <head> < ...

  3. Flume学习应用:Java写日志数据到MongoDB

    概述 Windows平台:Java写日志到Flume,Flume最终把日志写到MongoDB. 系统环境 操作系统:win7 64 JDK:1.6.0_43 资源下载 Maven:3.3.3下载.安装 ...

  4. Sd - JavaBase问题

    1. Java有哪些基本数据类型 2. Java基本数据类型和引用类型的区别 3. Java的多态 4. Override和Overload的区别 5. Java内部类 6. 继承和组合的比较 7. ...

  5. 【POJ 2409】Let it Bead

    http://poj.org/problem?id=2409 Burnside引理:设\(G\)是\(X\)的置换群,而\(\mathcal{C}\)是\(X\)中一个满足下面条件的着色集合:对于\( ...

  6. 【二分】Subsequence

    [POJ3061]Subsequence Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15908   Accepted:  ...

  7. BZOJ 4939 [Ynoi2016]掉进兔子洞(莫队+bitset)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4939 [题目大意] 给出一个数列,每个询问给出三个区间,问除去三个区间共有的数字外, ...

  8. 【启发式搜索】【A*算法】hdu6171 Admiral

    一个舰队的目标状态如上图.红色是旗舰.然后给你初始局面,每一次决策可以把旗舰和其上一层或下一层的两个相邻的进行交换.如果能在20步内出解的话,输出最小步数:否则输出“too difficult”. 把 ...

  9. 实验三 敏捷开发与XP实践实验报告

    实验三 敏捷开发与XP实践实验报告 实验内容 1. XP基础 2. XP核心实践 3. 相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vi ...

  10. Problem D: 指针:调用自定义排序函数sort,对输入的n个数进行从小到大输出。

    #include<stdio.h> int sort(int *p,int n) { int i,j,temp; ;i<n-;i++) for(j=i;j<n;j++) if( ...