Netty利用ChannelGroup广播消息
在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广播消息的更多相关文章
- rabbitMQ应用,laravel生产广播消息,springboot消费消息
最近做一个新需求,用户发布了动态,前台需要查询,为了用户读取信息响应速度更快(MySQL很难实现或者说实现起来很慢),所以在用户动态发布成功后,利用消息机制异步构建 redis缓存 和 elastic ...
- node的socket.io的广播消息
在多个客户端与服务器端建立连接后,socket.io()服务器具有一个sockets属性,属性值为所有与客户端建立连接的socket对象.可以利用该对象的send方法或emit方法向所有客户端广播消息 ...
- Linux下UDP收/发广播消息简单实现
发送广播消息 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<sys/typ ...
- Linux系统下UDP发送和接收广播消息小例子
// 发送端 #include <iostream> #include <stdio.h> #include <sys/socket.h> #include < ...
- 利用System V消息队列实现回射客户/服务器
一.介绍 在学习UNIX网络编程 卷1时,我们当时可以利用Socket套接字来实现回射客户/服务器程序,但是Socket编程是存在一些不足的,例如: 1. 服务器必须启动之时,客户端才能连上服务端,并 ...
- 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了
系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...
- Android中利用Handler实现消息的分发机制(三)
在第二篇文章<Android中利用Handler实现消息的分发机制(一)>中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去 ...
- 利用rabbit_mq队列消息实现对一组主机进行命令下发
目的: 利用rabbit_mq队列消息实现对一组主机进行命令下发 server: #!/usr/bin/env python3.5 # -*- coding:utf8 -*- import os,sy ...
- Openfire开发广播服务接口,支持离线广播消息
Openfire开发广播服务接口,支持离线广播消息 概要 最近公司要求做一个web端向所有移动端发送公告,所以考虑到即时性就用openfire做服务.不过为了减轻web端的工作量,我们开发一个简单的插 ...
随机推荐
- java中常用的String方法
1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.length); 输出的结果是字符串长度10. 2 ...
- apache 把404页面的url转发给php脚本处理
# .htaccess1 RewriteCond %{REQUEST_FILENAME} !-f 2 RewriteRule ^(.*)$ map.php?host=%{HTTP_HOST}& ...
- shell 倒引号
`command` 倒引号 (backticks) 在前面的单双引号,括住的是字串,但如果该字串是一列命令列,会怎样?答案是不会执行.要处理这种情况,我们得用倒单引号来做. fdv=`date +%F ...
- 【BZOJ 3238】【AHOI 2013】差异
http://www.lydsy.com/JudgeOnline/problem.php?id=3238 后缀数组裸题但是\(5\times 10^5\)貌似常数有点大就过不了?(我的sa常数那么大想 ...
- [Luogu2540][NOIP2016]斗地主增强版(搜索+DP)
增强版就是原版中两鬼不算对子的版本. 先爆搜出完所有对子,剩下的牌DP处理. 考虑每个数码的拆牌情况,最多可能被拆成5种情况:1+1+1+1,1+1+2,1+3,2+2,4.故DP状态数最多为5^13 ...
- 【最大权森林/Kruskal】POJ3723-Conscription
[题目大意] 招募m+n个人每人需要花费$10000,给出一些关系,征募某个人的费用是原价-已招募人中和他亲密值的最大值,求最小费用. [思路] 人与人之间的亲密值越大,花费越少,即求出最大权森林,可 ...
- <摘录>perl正则表达式中的元字符、转义字符、量词及匹配方式
Linux平台上被广泛使用的正则表达式库PCRE - Perl-compatible regular expressions,从其名字即可知道,PCRE提供的是一套与Perl中相兼容的正则表达式. 元 ...
- 改变element-ui滚动条设置,
基于vue的滚动条组件之--element隐藏组件滚动条scrollbar使用 在项目中,总是需要用到滚动条,但windows浏览器默认的滚动条是很丑的,为了页面美观,可以考虑优化滚动条样式. vu ...
- OM-销售订单行【订购项目】配置参数文件控制
ONT_RESTRICT_CUST_ITEMS OM:限制行层收货地址的客户项目 ONT_USE_MVIEW_FOR_ITEMS_LOV OM:为项目值列表使用物化视图(遵守项目可订购性规则)
- win7怎么设置1440*900分辨率
右击桌面打开nvidia显卡控制面板显示一栏里面选择更改分辨率如果里面没有你要求的1440*900, 点下面的那个自定义,创建自定义分辨率,水平像素填1440,垂直扫描线填900. 创建完就可以应用了