什么是Netty?Netty是一个框架。或者说是一个工具集。封装了网络编程方面java的API。
Netty有哪些核心组件?
1、 Channel:java nio的基本构造,代表一个实体(硬件设备、文件、网路套接字等)的开放连接。用作传入(入站)或者传出(出站)数据
2、 回调:封装操作完成后需要做的事情的方法
3、 Future: 提供异步操作的结果访问
4、 事件和ChannelHandler:程序运行过程中发生的事情抽象(事件)交给ChannerHandler来处理,channelHandler类似于为了响应特定事件而执行的回调
Netty的Hello world
server
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public static void main(String[]args)throws Exception{
new EchoServer(8888).start();
}
public void start() throws Exception{
final EchoServerHandler handler = 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
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(handler);
}
});
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
}finally {
group.shutdownGracefully().sync();
}
}
}
serverHandler
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf in = (ByteBuf) msg;
System.out.printf("Server get:"+in.toString(CharsetUtil.UTF_8));
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//将目前暂存于ChannelOutboundBuffer中的消息在下一次flush或者writeAndFlush的时候冲刷到远程并关闭这个channel
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
client
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 b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)//指定NIO的传输方式
.remoteAddress(new InetSocketAddress(host,port))//指定远程地址
.handler(new ChannelInitializer<SocketChannel>() {//向channel的pipeline添加handler
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());//channelHander交给pipeline
}
});
ChannelFuture f = b.connect().sync();//连接到远程节点,阻塞直到连接完成
System.out.println("wait");
f.channel().closeFuture().sync();//阻塞直到连接关闭
System.out.println("over");
}finally {
System.out.println("shutdown");
group.shutdownGracefully().sync();//关闭线程池并且释放资源
}
}
public static void main(String[]args) throws Exception{
new EchoClient("localhost",8888).start();
}
}
clientHandler
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello world",CharsetUtil.UTF_8));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
System.out.println("Client get:"+msg.toString(CharsetUtil.UTF_8));
}
}
Channel、Eventloop 、ChannelFuture 是什么关系?
它们是netty对网络的抽象组件。
Channel本身用来提供基本的IO操作(bind/connect/read/write),连接建立之后通过EventLoop来处理所发生的事情,它们之间的对应关系是1个channel只能有1个EventLoop,但是一个EventLoop对应多个Channel。EventLoop整个生命周期中只和一个Thread绑定,对应来讲一个Channel中的所有IO操作也都是在一个线程中执行的。执行的结果则是通过ChannelFuture来获取
Channel有什么特征?
1、 channel是传输API的核心,每一个都会被分配一个ChannelPipeline和ChannelConfig,ChannelConfig包含了Channel的所有配置,并且支持热更新
2、 每个channel都是独一无二的,channel之间的顺序通过Comparable来实现比较
3、 channel的实现是线程安全的
pipeline和handler是什么关系?
pipeline用来管理数据流,handler(client和server)是用来处理逻辑。
ChannelHandler接收事件,对事件进行逻辑处理,并将数据传给链(多个按照一定顺序定义的ChannelHandler)中的下一个ChannelHandler。ChannelPipLine就是ChannelHandler的编排顺序(二者建立关系的时机是ChannelInitializer执行initChannel的时候ChannelPipline组装自定义的channelHandler)。出于方便ChannelHandler会提供一些适配实现类让用户专注于处理自己的业务逻辑。
bootstrap是什么?
有两种类型,客户端(简称BootStrap)和服务端(简称ServerBootStrap)。区别有两点
1、 BootStrap用来连接远程节点,ServerBootStrap则是绑定本地端口监听连接
2、 客户端需要一个EventLoopGroup(存多个EventLoop的东西),服务端需要两个(可以是同一个实例),一个用来绑定到本地端口代表已经监听了(分配一个EventLoop),另一个则是处理客户端的连接(再分配一个EventLoop)
Netty支持的传输类型有哪些?
- NIO:基于java api的selector机制实现。 大致原理是:当channel状态发生变化的时得到通知,执行状态变化相应的任务,响应结束后,选择器重置,再次重复这个过程
- Epoll:只能在linux系统中使用,高负载情况下,性能优于JDK的NIO。 大致原理是:I/O多路复用【通过一个文件符管理多个文件描述符(针对epoll可以看做无限制)】,当一个文件描述符可读或者可写的时候,收到通知,立马执行【边沿触发】
- OIO(旧的阻塞IO):基于java.net的阻塞IO。 大致原理是:单线程监听一个socket,任何I/O操作在任意的时间节点上都有可能被阻塞
- Local:同一个JVM上运行的客户端和服务端之间的通信
- Embedded:使用channel,但不需要真正意义上的网络传输,一般用于测试
附录
Netty In Action