天气:晴
今天学习内容:
一、Netty的handler链调用机制
1.netty的逐渐主要有Channel、EventLoop、ChannelFuture、ChanneHandler、ChannelPipe等
2.ChannelHandler充当了处理入站出站数据应用程序逻辑的容器
编写server:
public class MyServer{
public static void main(String[] args) throws Exception{
//创建两个组
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new MyServerInitializer());//自定义一个初始化类
ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
channelFuture.channel().closeFuture().sync();
}finally{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
编写一个服务器初始化类MyServerInitializer
public class MyServerInitializer extends ChannelInitializer<SockerChannel>{
@Override
protected void initChannel(SocketChannel ch) throw Exception{
ChannelPipeline pipeline = ch.pipeline();
//入站的handler 进行解码MyByteTolongDecoder
pipeline.addLast(new MyByteTolongDecoder
());
//编写一个自定义handler处理业务逻辑
pipeline.addLast(new MyServerHandler
());
}
编写一个MyByteTolongDecoder
public class MyByteTolongDecoder extends ByteToMessageDecoder{
@Override
protected void decode(ChannelHandlerContext ctx,ByteBuf in, List<Object> out)throws Exception{
//ctx是上下文对象
//in是入站的bytebuf
//out是list集合,将解码后的数据传给下一个handler
System.out.println("MyByteTolongDecoder
类的decode方法被调用");
//因为long是八个字节
if(in.readableBytes() >= 8){
out.add(in.readLong());
}
}
编写一个MyServerHandler
public class MyServerHandler extends SimpleChannelInboundHandler<long>{
@Override
protected coid channelRead0(ChannelHandlerContext ctx,Long msg) throws Exception{
System.out.println("从客户端" + ctx.channel().remoteAddress() + "读取到long" +msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause) throws Exception{
cause.printStackTrace();
ctx.close();
}
}
编写一个客户端MyClient
public class MyClient{
public static void main(String[] args) throws Exception{
EcentLoopGroup group = new NioEVentLoopGroup();
try{
Bootstrap bootstrap = new Bootstrap();
bootstap.group(group).channel(NioSocketChannel.class).handler(new MyClientInitializer());//自定义一个初始化类
//绑定地址拿到一个channelFuture
ChannelFuture channelFuture = bootstrap.connect("locahost",7000).sync();
channelFuture.channel().closeFuture().sync();
}finally{
group.shutdownGracefully();
}
}
编写一个MyClientInitializer
public class MyClientInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel ch) throws Exception{
ChannelPopeline pipeline = ch.pipeline();
//加入一个出站handler对数据进行一个编码
pipeline.addLast(new MyLongToByteEncoder());
//加入一个自定义的handler,处理业务
pipeline.addLast(new MyClientHandler());
编写一个出站编码的handler
public class MyLongToByteEncoder extends MessageToByteEncoder<Long>{
@Override
protected void encode(ChannelHandlerContext ctx,Long msg,ByteBuf out) throws Exception{
System.out.println("MyLongToByteEncoder类的encode方法被调用");
System.out.println("msg=" + msg);
out.writeLong(msg);
}
}
编写一个处理业务的MyClientHandler
public class MyClientHandler extends SimpleChannelInboundHandler<Long>{
@Override
protected void channelRead0(ChannelHandlerContext ctx,Long msg) throws Exception{
}
//重写channelActive发送数据
@override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
System.out.println("MyClientHandler 发送数据");
//ctx.writeAndflush(Unpooled.copiedBuffer("dwwdw"));
ctx.writeAndFlush(1232425L);//直接发送一个long
}
拓展:
1.发送的内容如果不符合编码器泛型,会跳过处理直接传递给下一个handler;
2.编码器每读取一次都会传递给下一个handler,所以可能会出现多次调用handler的情况,比如上面发送的不是一个long而是一个长字符串,会触发多次MyServerHandler