Netty:ChannelInitializer添加到ChannelPipeline完成任务以后会自动删除自己

说明

io.netty.channel.ChannelInitializer是一个特殊的ChannelInboundHandler。它的主要作用是向 Channel对应的ChannelPipeline中增加ChannelHandler。执行完ChannelInitializer的initChannel(C ch)函数以后,ChannelInitializer就会从ChannelPipeline自动删除自己,防止重复进入。

一般是通过Bootstrap.handler(ChannelHandler) 、ServerBootstrap.childHandler(ChannelHandler)的方式分别在客户端、服务端中将ChannelInitializer这个ChannelHandler增加到ChannelPipeline中。

示例

思路

我们来验证下ChannelInitializer是否会被自动删除。我们在ChannelInitializer的initChannel(C ch)函数末尾打印出来当前ChannelPipeline中已经添加的ChannelHandler名称;在Channel连接成功以后,再打印出来当前ChannelPipeline中已经添加的ChannelHandler名称,两者对照下,就能看出来是否被自动删除了。

代码片段

复制代码
package com.thb.power.terminal;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import com.thb.power.packet.register.RegisterRequestPacket;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * 主函数
 * @author thb
 *
 */
public class Terminal {
	// 要连接的服务端的host 
	static final String HOST = System.getProperty("host", "127.0.0.1"); 
	// 要连接的服务端的端口号 
	static final int PORT = Integer.parseInt(System.getProperty("port", "22335"));

	public static void main(String[] args) throws Exception {
		// 配置客户端
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap b = new Bootstrap();
			b.group(group)
			 .channel(NioSocketChannel.class)
			 .option(ChannelOption.TCP_NODELAY, true)
			 .handler(new TerminalInitializer());
			
			// 启动客户端
			Channel ch = b.connect(HOST, PORT).sync().channel();		
			
			// 查看ChannelPipeline添加的ChannelHandler名称
			System.out.println("after channel connected:");
			for (String name : ch.pipeline().names()) {
				System.out.println("handler name: " + name);
			} 
			
			ChannelFuture lastWriteFuture = null;
			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			System.out.println("please input(register):");
			for (;;) {
				String line = in.readLine();
				if (line == null) {
					break;
				}				

				// 如果用户输入register,表示命令客户端发送注册请求给服务器
				if (line.toLowerCase().equals("register")) {
					RegisterRequestPacket registerRequest = new RegisterRequestPacket();
					// 返回的ByteBuf存放着注册请求的数据
					ByteBuf buf = registerRequest.build(ch);
					
					lastWriteFuture = ch.writeAndFlush(buf);						
				}
			}
			
			if (lastWriteFuture != null) {
				lastWriteFuture.sync();
			}
		} finally {
			// 关闭event loop以便终止所有的线程
			group.shutdownGracefully();
		}

	}

}


// ChannelInitializer的子类
package com.thb.power.terminal;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class TerminalInitializer extends ChannelInitializer<SocketChannel> {

	 @Override
	 public void initChannel(SocketChannel ch) throws Exception {
		 ChannelPipeline p = ch.pipeline();
		 p.addLast(new LoggingHandler(LogLevel.INFO));
		 
		 // 查看ChannelPipeline添加的ChannelHandler名称
		 System.out.println("in initChannel(SocketChannel ch) method of TerminalInitializer:");
		 for (String name : ch.pipeline().names()) {
			 System.out.println("handler name: " + name);
		 } 
	 }
}

运行输出

从上面输出可以看出,ChannelInitializer开始被添加到ChannelPipeline中,后来又被自动删除了。

相关推荐
77qqqiqi16 分钟前
正则表达式
java·后端·正则表达式
厦门德仔40 分钟前
【WPF】WPF(样式)
android·java·wpf
大春儿的试验田41 分钟前
高并发收藏功能设计:Redis异步同步与定时补偿机制详解
java·数据库·redis·学习·缓存
Gappsong87444 分钟前
【Linux学习】Linux安装并配置Redis
java·linux·运维·网络安全
hqxstudying1 小时前
Redis为什么是单线程
java·redis
RainbowSea1 小时前
NVM 切换 Node 版本工具的超详细安装说明
java·前端
逆风局?1 小时前
Maven高级——分模块设计与开发
java·maven
周某某~1 小时前
maven详解
java·maven
读书点滴1 小时前
笨方法学python -练习14
java·前端·python
lingRJ7771 小时前
微服务架构下的抉择:Consul vs. Eureka,服务发现该如何选型?
java·eureka·springcloud·consul·backend·microservices·servicediscovery