认识netty
什么是netty
- netty是一个利用java的高级网络的能力,隐藏其背后的复杂性而提供一个易于使用的API的客服端/服务器框架。
netty与Tomact有什么区别
- netty和Tomcat最大的区别就在于通信协议,Tomcat是基于Http协议的,它的实质是一个基于http协议的web容器,但事netty不一样,他能通过编程自定义各种协议,因为netty能够通过codec自己来编码/解码字节流,完成类似redis访问的功能,这就是netty和Tomcat最大的不同
netty为什么受欢迎
-
netty是一款受到大公司青睐的框架,netty能够受到青睐的原因有三:
-
并发高
netty是一款基于NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比BIO(Blocking I/O,阻塞IO),它的并发性能得到了很大提高。一下两张图是BIO和NIO
阻塞io通信方式
非阻塞io
-
传输快
netty的传输快其实也是依赖NIO的另一个特性–零拷贝。在java中,内存分为堆内存、栈内存和字符串常量池,其中堆内存是占用内空间最大的一块,也是java对象存放的地方,一般我们的数据如果需要从IO读取到堆内存,中间需要经过socket缓冲区,也就是说一个数据会被朝北两次才能到达它的终点,如果数据量大,就会造成不必要的浪费。netty针对这种情况,使用了零拷贝,当它需要接收数据的时候,它会在堆内存中开辟一块内存,数据就直接从IO读到了那块内存中,在netty里面通过ByteBuf可以直接对这些数据进行操作,从而加快了传输速度。
-
封装好
直接上代码。
BIO:
public class PlainNioServer { public void serve(int port) throws IOException { ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); ServerSocket ss = serverChannel.socket(); InetSocketAddress address = new InetSocketAddress(port); ss.bind(address); //1 Selector selector = Selector.open(); //2 serverChannel.register(selector, SelectionKey.OP_ACCEPT); //3 final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes()); for (;;) { try { selector.select(); //4 } catch (IOException ex) { ex.printStackTrace(); // handle exception break; } Set<SelectionKey> readyKeys = selector.selectedKeys(); //5 Iterator<SelectionKey> iterator = readyKeys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); try { if (key.isAcceptable()) { //6 ServerSocketChannel server = (ServerSocketChannel)key.channel(); SocketChannel client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, msg.duplicate()); //7 System.out.println( "Accepted connection from " + client); } if (key.isWritable()) { //8 SocketChannel client = (SocketChannel)key.channel(); ByteBuffer buffer = (ByteBuffer)key.attachment(); while (buffer.hasRemaining()) { if (client.write(buffer) == 0) { //9 break; } } client.close(); //10 } } catch (IOException ex) { key.cancel(); try { key.channel().close(); } catch (IOException cex) { // 在关闭时忽略 } } } } } }
netty:
public class NettyOioServer { public void server(int port) throws Exception { final ByteBuf buf = Unpooled.unreleasableBuffer( Unpooled.copiedBuffer("Hi!\r\n", Charset.forName("UTF-8"))); EventLoopGroup group = new OioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); //1 b.group(group) //2 .channel(OioServerSocketChannel.class) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() {//3 @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { //4 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);//5 } }); } }); ChannelFuture f = b.bind().sync(); //6 f.channel().closeFuture().sync(); } finally { group.shutdownGracefully().sync(); //7 } } }
从代码上看,netty就已经秒杀传统socket编程了,下面介绍一下netty中重要的概念。
-
netty重要概念
-
Channel
数据传输刘,与channel相关的概念有一下四个,如图:
- Channel:表示一个连接,可以理解为一个请求,就是一个Channel。
- ChannelHandler:核心处理业务就在之类,用于处理业务请求。
- ChannelHandlerContext:用于传输业务数据。
- ChannelPipline:用于保存处理过程需要用到的ChannelHandler和ChannelHandlerContext。
-
ByteBuf
ByteBuf是一个存储字节的容器,最大的特点就是使用方便,它既有自己的读索引和写索引,方便对争端字节缓存进行读写,也支持get/set,方便对其中每一个字节进行读写,它的数据结构入下:
-
Codec
netty中的编码/解码器,通过它能完成字节与pojo、pojo与byte的相互转换,从而达到自定义协议的目的。
读写,也支持get/set,方便对其中每一个字节进行读写,它的数据结构入下:
[外链图片转存中…(img-fwAH71LD-1644737484407)]
-
Codec
netty中的编码/解码器,通过它能完成字节与pojo、pojo与byte的相互转换,从而达到自定义协议的目的。
在netty里面最有名的就是HttpRequestDecoder和HttpResponseEncoder了。