是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。基于Nio的
特点? 高并发,基于Nio的传输快,使用零拷贝,减少不必要的内存拷贝封装好,简化了Nio的API高性能体现:IO线程模型,内存零拷贝,内存池设计,申请的内存可以重复使用,指直接内存,高性能序列化协议。 TCP粘包/拆包问题和解决 是什么:TCP是基于流进行传输数据,可能把数据拆成几个包。也可能把几个小的数据封装成一个大的包发送
粘包就是,小的数据合并一个大的包。
拆包就是:大的数据,超过了TCP报文最大长度,就会拆包。
解决就是:类似编码解码,拆包和粘包用同样的协议。Netty中已经有了拆包器。
ch.pipeline().addLast(new FixedLengthframeDecoder(31)); Netty的零拷贝
传统发送数据的四次拷贝
1.数据从磁盘拷贝的内存的read buffer
2、数据从read buffer拷贝到用户缓存区
3、从用户缓存区拷贝到内存的Socket buffer
4、从内核Socket buffer拷贝到网卡缓存区
零拷贝就是省略第2和第3步。
Netty中零拷贝的体现:
1.bytebuffer,使用的是堆外内存直接进行Socket读写。传统的JVM会将堆内数据拷贝一份到直接内存,然后写入Socket,多一次内存拷贝。
2.组合buffer对象,两个buffer组合在一起不是新申请一个大的buffer,而是使用组合buffer保留这两个buffer的引用。
3、文件传输FileChannnel.transferTo,就是省略第2第3步。
package com.example.demo.netty;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.*;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;public class Myserver { public static void main(String[] args) { //1.创建两个线程组 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); //2.创建服务器启动对象,设置参数 ServerBootstrap bootstrap = new ServerBootstrap(); //设置两个线程池组 bootstrap.group(bossGroup,workerGroup) //设置服务端通道实现类型 .channel(NioServerSocketChannel.class) //设置线程队列得到连接个数 .option(ChannelOption.SO_BACKLOG,128) //设置保持活动连接状态 .childOption(ChannelOption.SO_KEEPALIVE,true) //使用匿名内部类初始化通道对象 .childHandler(new ChannelInitializer
package com.example.demo.netty;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.util.CharsetUtil;public class MyServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //获取客户端发送的消息 ByteBuf byteBuf = (ByteBuf) msg; System.out.println("收到客户端" + ctx.channel().remoteAddress() + "发送的消息:" + byteBuf.toString(CharsetUtil.UTF_8)); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { //发送消息给客户端 ctx.writeAndFlush(Unpooled.copiedBuffer("服务端已收到消息", CharsetUtil.UTF_8)); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { //发生异常,关闭通道 ctx.close(); }}
创建客户端启动类package com.example.demo.netty;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;public class MyClient { public static void main(String[] args) { NioEventLoopGroup eventExecutors = new NioEventLoopGroup(); //创建bootStrap对象,配置参数 Bootstrap bootstrap = new Bootstrap(); //设置线程组 bootstrap.group(eventExecutors) .channel(NioSocketChannel.class) .handler(new ChannelInitializer
package com.example.demo.netty;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelHandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import io.netty.util.CharsetUtil;import io.netty.util.concurrent.EventExecutorGroup;public class MyClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { //发送消息到服务端 ctx.writeAndFlush(Unpooled.copiedBuffer("你好", CharsetUtil.UTF_8)); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf byteBuf = (ByteBuf) msg; System.out.println("收到服务端" + ctx.channel().remoteAddress() + "的消息:" + byteBuf.toString(CharsetUtil.UTF_8)); }}