本章内容是观看《netty实战》书籍前7章,并且在B站重新找了一个学习视频,然后在观看部分课程后整理的。
不足之处
boosGroup 相当于一个组长
workerGroup相当于手下的员工
boosGroup将连接成功的通道分配给workerGroup
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
…………
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)//分配任务队列
.childOption(ChannelOption.SO_KEEPALIVE,true)
.handler(new LoggingHandler(LogLevel.INFO))// bossGroup 增加日志处理器
聊天室
服务器配置类
public class ChatServer {
private int port;
public ChatServer(int port) {
this.port = port;
}
public void run() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,128)
.childOption(ChannelOption.SO_KEEPALIVE,true)
.handler(new LoggingHandler(LogLevel.INFO))// bossGroup 增加日志处理器
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder",new StringDecoder());//解码器
pipeline.addLast("encoder",new StringEncoder());//编码器
//当满足该条件后,会传递个下一个handler 在userEventTiggered方法中处理
pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
pipeline.addLast("myServerHandler",new ChatServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
System.out.println("服务器启动完成");
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new ChatServer(6888).run();
}
}
服务器处理类
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
//GlobalEventExecutor.INSTANCE 全局事件执行器 单例
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//一旦连接 第一个被执行
//将当前channel 加入到组中
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
//底层自动循环
channelGroup.writeAndFlush("客户端:" + channel.remoteAddress() + "加入聊天\n");
channelGroup.add(channel);
}
//断开连接
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
//channelGroup.remove(channel) 当触发handlerRemoved 会自动去除当前channel
channelGroup.writeAndFlush("客户端:" + channel.remoteAddress() + "离开聊天\n");
}
//表示channel处于活动状态
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + "在"+simpleDateFormat.format(new Date())+"上线了\n");
}
//表示channel不处于活动状态
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + "在"+simpleDateFormat.format(new Date())+"离线了\n");
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
final Channel channel = ctx.channel();
//根据不同身份 发送信息(自己)
channelGroup.forEach(ch -> {
if (channel != ch) {//不是当前的通道
ch.writeAndFlush("[客户]" + channel.remoteAddress() + "在"+simpleDateFormat.format(new Date())+"发送信息:" + msg+"\n");
}else{
ch.writeAndFlush("[自己]在"+simpleDateFormat.format(new Date())+"发送了消息:"+msg+"\n");
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
cause.printStackTrace();
}
/**
* @Date: 2020/10/28 4:43 下午
* @Param: evt 事件
* @Param: ctx 上下文
* @Author: Lmy
* @Description:
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if(evt instanceof IdleStateEvent){
IdleStateEvent event = (IdleStateEvent) evt;
String eventType=null;
switch (event.state()){
case READER_IDLE:
eventType="读空闲";
break;
case WRITER_IDLE:
eventType="写空闲";
break;
case ALL_IDLE:
eventType="读写空闲";
break;
}
System.out.println(ctx.channel().remoteAddress()+"-->超时事件发生:"+eventType);
}
}
}
客户端
客户端配置类
private final String host;
private final int prot;
public ChatClient(String host, int prot) {
this.host = host;
this.prot = prot;
}
private void run() throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("encoder",new StringEncoder());
pipeline.addLast("decoder",new StringDecoder());
pipeline.addLast("myHandler",new ChatClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect(host, prot).sync();
Channel channel = channelFuture.channel();
System.out.println("————"+channel.localAddress()+"————");
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String msg = scanner.nextLine();
channel.writeAndFlush(msg+"\r\n");
}
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new ChatClient("127.0.0.1",6888).run();
}
客户端处理类
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(msg.trim());
}