-
pipeline 与 channelHandler 的构成
无论是从服务端来看,还是客户端来看,在 Netty 整个框架里面,一条连接对应着一个 Channel,这条 Channel 所有的处理逻辑都在一个叫做
ChannelPipeline
的对象里面,ChannelPipeline
是一个双向链表结构,他和 Channel 之间是一对一的关系。
ChannelPipeline
里面每个节点都是一个ChannelHandlerContext
对象,这个对象能够拿到和 Channel 相关的所有的上下文信息,然后这个对象包着一个重要的对象,那就是逻辑处理器ChannelHandler
。
-
实验
服务端:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
public class NettyServer {
public static void main(String[] args) {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();
ChannelFuture channelFuture = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
// inBound,处理读数据的逻辑链
ch.pipeline().addLast(new MyInboundServerHandlerA());
ch.pipeline().addLast(new MyInboundServerHandlerB());
ch.pipeline().addLast(new MyInboundServerHandlerC());
// outBound,处理写数据的逻辑链
ch.pipeline().addLast(new MyOutboundServerHandlerA());
ch.pipeline().addLast(new MyOutboundServerHandlerB());
ch.pipeline().addLast(new MyOutboundServerHandlerC());
}
}).bind(9999);
channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
if (future.isSuccess()) {
System.out.println("端口绑定成功!");
} else {
System.err.println("端口绑定失败!");
}
}
});
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class MyInboundServerHandlerA extends ChannelInboundHandlerAdapter {
//收到数据之后调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("MyInboundServerHandlerA");
super.channelRead(ctx,msg);
}
}
class MyInboundServerHandlerB extends ChannelInboundHandlerAdapter {
//收到数据之后调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("MyInboundServerHandlerB");
super.channelRead(ctx,msg);
}
}
class MyInboundServerHandlerC extends ChannelInboundHandlerAdapter {
//收到数据之后调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("MyInboundServerHandlerC");
ctx.channel().writeAndFlush(msg);
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
public class MyOutboundServerHandlerA extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("MyOutboundServerHandlerA");
super.write(ctx, msg, promise);
}
}
class MyOutboundServerHandlerB extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("MyOutboundServerHandlerB");
super.write(ctx, msg, promise);
}
}
class MyOutboundServerHandlerC extends ChannelOutboundHandlerAdapter {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("MyOutboundServerHandlerC");
super.write(ctx, msg, promise);
}
}
客户端:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import java.net.InetSocketAddress;
public class NettyClient {
public static void main(String[] args) {
EventLoopGroup client = new NioEventLoopGroup();
ChannelFuture channelFuture = new Bootstrap()
.group(client)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 指定连接数据读写逻辑
pipeline.addLast(new MyClientHandler());
}
})
.connect(new InetSocketAddress("127.0.0.1", 9999));
channelFuture.addListener(new GenericFutureListener<Future<? super Void>>() {
@Override
public void operationComplete(Future<? super Void> future) throws Exception {
if (future.isSuccess()) {
System.out.println("连接成功");
} else {
System.out.println("连接失败");
}
}
});
}
}
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.AttributeKey;
import java.nio.charset.Charset;
/**
* 向服务端写数据的处理器
*/
public class MyClientHandler extends ChannelInboundHandlerAdapter {
public static final AttributeKey<Boolean> CLIENT_FLAG = AttributeKey.newInstance("flag");
//在客户端连接建立成功之后被调用
@Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("客户端向服务端写出数据");
// 写数据并发送
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
byteBuf.writeBytes("传输的数据".getBytes());
ctx.channel().writeAndFlush(byteBuf);
}
//收到数据之后调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("客户端读到数据:"+((ByteBuf)msg).toString(Charset.forName("utf-8")));
}
}
输出结果 :
端口绑定成功!
MyInboundServerHandlerA
MyInboundServerHandlerB
MyInboundServerHandlerC
MyOutboundServerHandlerC
MyOutboundServerHandlerB
MyOutboundServerHandlerA
pipeline 的执行顺序
- channelHandler 分为 inBound 和 outBound 两种类型的接口,分别是处理数据读与数据写的逻辑
- 两种类型的 handler 均有相应的默认实现,默认会把事件传递到下一个,这里的传递事件其实说白了就是把本 handler 的处理结果传递到下一个 handler 继续处理。
- inBoundHandler 的执行顺序与我们实际的添加顺序相同,而 outBoundHandler 则相反。
- 虽然两种类型的 handler 在一个双向链表里,但是这两类 handler 的分工是不一样的,inBoundHandler 的事件通常只会传播到下一个 inBoundHandler,outBoundHandler 的事件通常只会传播到下一个 outBoundHandler,两者相互不受干扰。