BroadCastServer.java
package com.hikvision.bc;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class BroadCastServer {
private 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() {
@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();
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
public static void main(String[] args) {
BroadCastServer.run(8080);
}
}
Client.java
package com.hikvision.bc;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
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);
private static void start() {
for (int i = 0; i < 5; i++) {
es.execute(new Task());
}
es.shutdown();
}
public static class Task implements Runnable {
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() {
@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();
}
}
BroadCastChannelHandler.java
package com.hikvision.bc;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.inject.spi.Message;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelMatcher;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
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 {
public boolean matches(Channel channel) {
return true;
}
}
}
SimpleClientChannelHandler.java
package com.hikvision.bc;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
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.java
package com.hikvision.bc;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.channel.group.ChannelMatcher;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
public class ChannelGroups {
private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup("ChannelGroups", GlobalEventExecutor.INSTANCE);
static void add(Channel channel) {
CHANNEL_GROUP.add(channel);
}
public static ChannelGroupFuture broadcast(Object msg) {
return CHANNEL_GROUP.writeAndFlush(msg);
}
static ChannelGroupFuture broadcast(Object msg, ChannelMatcher matcher) {
return CHANNEL_GROUP.writeAndFlush(msg, matcher);
}
public static ChannelGroup flush() {
return CHANNEL_GROUP.flush();
}
static boolean discard(Channel channel) {
return CHANNEL_GROUP.remove(channel);
}
static ChannelGroupFuture disconnect() {
return CHANNEL_GROUP.disconnect();
}
public static ChannelGroupFuture disconnect(ChannelMatcher matcher) {
return CHANNEL_GROUP.disconnect(matcher);
}
static boolean contains(Channel channel) {
return CHANNEL_GROUP.contains(channel);
}
static int size() {
return CHANNEL_GROUP.size();
}
}