2019独角兽企业重金招聘Python工程师标准>>>
如题,只是为了实验,我将所有的客户端的channel存在静态变量ChannelGroup实例中,对消息进行群发。
当然,如果实际的环境中,我估计要将channel存在缓存数据库中,具体怎么做,后面再研究。
现在,我们来做这次简单的实验:
源代码:https://github.com/YangZhouChaoFan/netty-learn/tree/master/netty-start
1:NettyServer
package com.netty.start.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* 服务器类.
*/
public class NettyServer {
public void start(int port) throws Exception {
//创建接收者的事件循环组
EventLoopGroup parentGroup = new NioEventLoopGroup();
//创建访问者的事件循环组
EventLoopGroup childGroup = new NioEventLoopGroup();
try {
//创建服务器引导程序
ServerBootstrap b = new ServerBootstrap();
//设置消息循环
b.group(parentGroup, childGroup);
//设置通道
b.channel(NioServerSocketChannel.class);
//配置通道参数:连接队列的连接数
b.option(ChannelOption.SO_BACKLOG, 1024);
//设置客户端请求的处理操作
b.childHandler(new ChildChannelHandler());
//绑定端口,并获取通道io操作的结果
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
//关闭接收器事件循环
parentGroup.shutdownGracefully();
//关闭访问者的事件循环
childGroup.shutdownGracefully();
}
}
}
2:ChildChannelHandler
package com.netty.start.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 客户端通道处理类.
*/
public class ChildChannelHandler extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel e) throws Exception {
ChannelPipeline pipeline = e.pipeline();
// 以("\n")为结尾分割的 解码器
pipeline.addLast(new LineBasedFrameDecoder(1024));
// 字符串解码 和 编码
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
//添加消息处理
e.pipeline().addLast(new NettyServerHandler());
}
}
3:NettyServerHandler
package com.netty.start.server;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.SocketAddress;
/**
* 服务器处理类.
*/
public class NettyServerHandler extends ChannelHandlerAdapter {
static private Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
//创建频道组
public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 连接通道.
*
* @param ctx
* @param remoteAddress
* @param localAddress
* @param promise
* @throws Exception
*/
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
logger.info(remoteAddress + ":连接通道");
super.connect(ctx, remoteAddress, localAddress, promise);
}
/**
* 活跃通道.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":通道激活");
super.channelActive(ctx);
ctx.writeAndFlush("欢迎访问服务器\r\n");
channels.add(ctx.channel());
}
/**
* 非活跃通道.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":通道失效");
super.channelInactive(ctx);
channels.remove(ctx.channel());
}
/**
* 接收消息.
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":" + msg);
Channel currentChannel = ctx.channel();
for (Channel channel : channels) {
if (channel != currentChannel) {
channel.writeAndFlush("[" + currentChannel.remoteAddress() + "]" + msg + "\n");
}
}
}
/**
* 接收完毕.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
/**
* 关闭通道.
*
* @param ctx
* @param promise
* @throws Exception
*/
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":关闭通道");
super.close(ctx, promise);
}
/**
* 异常处理.
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.info("异常信息:" + cause.getMessage());
}
}
4:NettyClient
package com.netty.start.client;
import com.netty.start.server.ChildChannelHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 客户端类.
*/
public class NettyClient {
public void connect(String host, int port) throws Exception {
//创建事件循环组
EventLoopGroup group = new NioEventLoopGroup();
try {
//创建引导程序
Bootstrap b = new Bootstrap();
//设置消息循环
b.group(group);
//设置通道
b.channel(NioSocketChannel.class);
//配置通道参数:tcp不延迟
b.option(ChannelOption.TCP_NODELAY, true);
//设置通道处理
b.handler(new ChannelHandler());
//发起异步链接,等待输入参数
Channel channel = b.connect(host, port).sync().channel();
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
channel.writeAndFlush(in.readLine() + "\r\n");
}
} finally {
//关闭
group.shutdownGracefully();
}
}
}
5:ChannelHandler
package com.netty.start.client;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* 通道处理类.
*/
public class ChannelHandler extends ChannelInitializer {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
// 以("\n")为结尾分割的 解码器
pipeline.addLast(new LineBasedFrameDecoder(1024));
// 字符串解码 和 编码
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
socketChannel.pipeline().addLast(new NettyClientHandler());
}
}
6:NettyClientHandler
package com.netty.start.client;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.SocketAddress;
/**
* 客户端处理类.
*/
public class NettyClientHandler extends ChannelHandlerAdapter {
static private Logger logger = LoggerFactory.getLogger(NettyClientHandler.class);
/**
* 连接通道.
*
* @param ctx
* @param remoteAddress
* @param localAddress
* @param promise
* @throws Exception
*/
@Override
public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
logger.info(remoteAddress + ":连接通道");
super.connect(ctx, remoteAddress, localAddress, promise);
}
/**
* 活跃通道.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":通道激活");
super.channelActive(ctx);
}
/**
* 非活跃通道.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":通道失效");
super.channelInactive(ctx);
}
/**
* 接收消息.
*
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.info(ctx.channel().remoteAddress() + ":" + msg);
}
/**
* 接收完毕.
*
* @param ctx
* @throws Exception
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
/**
* 关闭通道.
*
* @param ctx
* @param promise
* @throws Exception
*/
@Override
public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
super.close(ctx, promise);
}
/**
* 异常处理.
*
* @param ctx
* @param cause
* @throws Exception
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.info("异常信息:" + cause.getMessage());
}
}
7:ServerTest
package com.netty.start.test;
import com.netty.start.server.NettyServer;
/**
* Created by chenhao on 2016/3/17.
*/
public class ServerTest {
public static void main(String[] args) throws Exception {
NettyServer server = new NettyServer();
server.start(3000);
}
}
8:ClientTest
package com.netty.start.test;
import com.netty.start.client.NettyClient;
/**
* Created by chenhao on 2016/3/17.
*/
public class ClientTest {
public static void main(String[] args) throws Exception {
NettyClient client = new NettyClient();
client.connect("127.0.0.1", 3000);
}
}
通过7和8两个类,启动测试实例。