netty学习笔记

来源:互联网 发布:淘宝客贷款哪里进 编辑:程序博客网 时间:2024/06/05 14:44
Netty是一个非阻塞、事件驱动的网络框架。Netty实际上是使用多线程处理IO事件。

一、netty的创建步骤:

1、创建EventLoopGroup;
2、创建ServerBootstrap;
3、指定使用NioServerSocketChannel;
4、使用指定的端口、设置套接字地址;
5、添加一个serverhandler/clienthandler;
6、异步绑定服务器;调用sync()方法阻塞等待,直到绑定完成;
7、获取channel的closeFuture,并且阻塞当前线程直到完成;
8、关闭EventLoopGroup,释放资源;

客户端:

import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.util.CharsetUtil;public class EchoClientHandler extends  SimpleChannelInboundHandler<ByteBuf> {@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {System.out.println("channelActive:将在一个连接建立时被调用");ctx.write(Unpooled.copiedBuffer("Netty rocks!",CharsetUtil.UTF_8));}protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {System.out.println("每当接收数据时,都会调用这个方法");System.out.println("Client received: " + msg.toString(CharsetUtil.UTF_8));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}@Overrideprotected void messageReceived(ChannelHandlerContext ctx, ByteBuf paramI) throws Exception {ctx.write(Unpooled.copiedBuffer("Netty rocks! messageReceived",CharsetUtil.UTF_8));System.out.println("client handler");}}

import java.net.InetSocketAddress;import io.netty.bootstrap.Bootstrap;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.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;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).remoteAddress(new InetSocketAddress(host, port)).handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ch.pipeline().addLast(new EchoClientHandler());}});ChannelFuture f = b.connect().sync();f.channel().closeFuture().sync();} finally {group.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoClient("localhost", 65535).start();}}

服务端:
import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;public class EchoServerHandler extends ChannelInboundHandlerAdapter {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf in = (ByteBuf) msg;System.out.println("Server received: " + in.toString());ctx.write(in);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx) throws Exception {ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();}}

import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.Channel;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;public class EchoServer {private final int port;public EchoServer(int port) {this.port = port;}public void start() throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {// create ServerBootstrap instanceServerBootstrap b = new ServerBootstrap();// Specifies NIO transport, local socket address// Adds handler to channel pipelineb.group(group).channel(NioServerSocketChannel.class).localAddress(port).childHandler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) throws Exception {ch.pipeline().addLast(new EchoServerHandler());}});// Binds server, waits for server to close, and releases resourcesChannelFuture f = b.bind().sync();System.out.println(EchoServer.class.getName() + "  started and listen on " + f.channel().localAddress());f.channel().closeFuture().sync();} finally {group.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoServer(65535).start();}}

二、netty的核心类

1、EventLoopGroup
EventLoopGroup包含一个或多个EventLoop,但只能使用一个特定的EventLoop。


2、Bootstrap:
一个Netty程序开始于Bootstrap类,Bootstrap类是Netty提供的一个可以通过简单配置来设置或"引导"程序的一个很重要的类


客户端使用Bootstrap,服务端使用ServerBootstrap。两者差别如下:
a、Bootstrap用来连接远程主机,有1个EventLoopGroup;
b、ServerBootstrap用来绑定本地端口,有2个EventLoopGroup
3、ChannelHandler:


三、缓冲buffer:

1、Netty缓冲API提供了几个优势:
2、可以自定义缓冲类型
3、通过一个内置的复合缓冲类型实现零拷贝
4、扩展性好,比如StringBuffer
5、不需要调用flip()来切换读/写模式
6、读取和写入索引分开
7、方法链
8、引用计数
9、Pooling(池
3种不同类型的ByteBuf:
a、Heap Buffer(堆缓冲区):最常用的类型是ByteBuf将数据存储在JVM的堆空间,这是通过将数据存储在数组的实 现。堆缓冲区可以快速分配,当不使用时也可以快速释放。它还提供了直接访问数组的方法,通过ByteBuf.array()来获取byte[]数据。
b、Direct Buffer(直接缓冲区):直接缓冲区,在堆之外直接分配内存。直接缓冲区不会占用堆空间容量,使用时应该考虑到应用程序要使用的最大内存容量以及如何限制它。直接缓冲区在使用Socket传递数据时性能很好,因为若使用间接缓冲区,JVM会先将数据复制到直接缓冲区再进行传递;但是直接缓冲区的缺点是在分配内存空间和释放内存时比堆缓冲区更复杂,而Netty使用内存池来解决这样的问题,这也是Netty使用内存池的原因之一。直接缓冲区不支持数组访问数据,但是我们可以间接的访问数据数组。
c、Composite Buffer(复合缓冲区):我们可以创建多个不同的ByteBuf,然后提供一个这些ByteBuf组合的视图。复合缓冲区就像一个列表,我们可以动态的添加和删除其中的ByteBuffer,JDK的ByteBuffer没有这样的功能。Netty提供了CompositeByteBuf类来处理复合缓冲
//创建复合缓冲区
CompositeByteBuf compBuf = Unpooled.compositeBuffer();
//创建堆缓冲区
ByteBuf heapBuf = Unpooled.buffer(8);
//创建直接缓冲区
ByteBuf directBuf = Unpooled.directBuffer(16);