一、基本概念
1、channel:通道,入站或者出站数据的载体
2、ChannelHandler:通道处理器,业务逻辑写在这里面,netty 5版本将入战和出站合并成了ChannelHandler
3、ChannelPipeline:通道里的管道,是一个或者多个ChannelHandler链的容器,当channel被创建时,会为该Channel自动分配一个ChannelPipeline,ChannelPipeline中可以放多个ChannelHandler。
4、ChannelHandlerContext:通道处理器上下文,代表了ChannelHandler和ChannelPipeline的关联关系,每当有ChannelHandler被添加到ChannelPipeline时就会创建一个ChannelHandlerContext。ChannelHandlerContext的主要功能是管理它所关联的ChannelHandler和在同一个ChannelPipeline中其他的ChannelHandler之间的交互。
5、ChannelHandlerAdapter:通道处理器的适配器,提供了入站和出站ChannelHandler的基本实现。
6、EventLoop与EventLoopGroup:称为事件循环,用来运行连着周期内发生的事件的。EventLoopGroup为每个新创建的Channel分配一个EventLoop。多个Channel可以共享一个EventLoop。
7、SimpleChannelInboundHandler:可以用来接收解码消息,无需手动释放资源。
8、引导:作用是创建Channel组装成可运行的程序。分为客户端引导和服务端引导。客户端引导:为客户端应用程序创建Channel当调用bind()或者connect()方法时就会创建一个Channel。服务器引导:当bind()方法被调用时会创建一个ServerChannel,当有客户端连接并且服务器端接受时,ServerChannel会创建相应的Channel进行通信。
9、ChannelInitializer:通道Channel初始化时调用。
10、入站和出站:入站是指数据从网络层流向你的应用程序,出战是指数据从应用程序流向网络层。在ChannelPipeline的流向,入站是从头到尾,出站是从尾流向头部。
11、注意:ChannelHandler的实现类,如果被标记为@Sharable,则代码该处理器可以被添加到多个ChannelPipeline中去。
二、搭建一个简单的客户端和服务端
1、安装依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha2</version>
</dependency>
2、客户端
2.1 新建处理器类:EchoClientHandler
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext ctx){
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg){
ByteBuf in = (ByteBuf) msg;
System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
}
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
cause.printStackTrace();
ctx.close();
}
}
2.2 新建客户端引导
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture future = bootstrap.connect().sync();
future.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClient("127.0.0.1", 2221).start();
}
}
3、服务器端
3.1 新建服务器端ChannelHandler
@ChannelHandler.Sharable
//@ChannelHandler.Sharable
public class EchoServerHandler extends SimpleChannelInboundHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg){
ByteBuf in = (ByteBuf) msg;
System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
ctx.write(in);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx){
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
cause.printStackTrace();
ctx.close();
}
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
}
}
3.2 新建服务器端引导
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
final EchoServerHandler serverHandler = new EchoServerHandler();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(serverHandler);
}
});
System.out.println("监听端口");
ChannelFuture f=b.bind().sync();
System.out.println("服务端关闭");
f.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoServer(2221).start();
}
}