NETTY TCP通信

什么事nettiy:

Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

为什么选择Netty

Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的,它已经得到成百上千的商用项目验证,例如Hadoop的RPC框架avro使用Netty作为底层通信框架;很多其他业界主流的RPC框架,也使用Netty来构建高性能的异步通信能力。

通过对Netty的分析,我们将它的优点总结如下:

1、API使用简单,开发门槛低;

2、 功能强大,预置了多种编解码功能,支持多种主流协议;

3、定制能力强,可以通过ChannelHandler对通信框架进行灵活地扩展;

4、 性能高,通过与其他业界主流的NIO框架对比,Netty的综合性能最优;

5、 成熟、稳定,Netty修复了已经发现的所有JDK NIO BUG,业务开发人员不需要再为NIO的BUG而烦恼;

6、社区活跃,版本迭代周期短,发现的BUG可以被及时修复,同时,更多的新功能会加入;

7、经历了大规模的商业应用考验,质量得到验证。在互联网、大数据、网络游戏、企业应用、电信软件等众多行业得到成功商用,证明了它已经完全能够满足不同行业的商业应用了。


NIO和IO的区别

IO                NIO
面向流            面向缓冲
阻塞IO            非阻塞IO
无                选择器


面向流与面向缓冲

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
阻塞与非阻塞IO

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。
选择器(Selectors)

Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
NIO和IO如何影响应用程序的设计

无论您选择IO或NIO工具箱,可能会影响您应用程序设计的以下几个方面:
1、 对NIO或IO类的API调用。
2、数据处理。
3、用来处理数据的线程数。


NETTY TCP NIO代码

maven依赖包

<dependency>  
        <groupId>io.netty</groupId>  
        <artifactId>netty-all</artifactId>  
        <version>4.1.4.Final</version>  
 </dependency> 


    import io.netty.bootstrap.ServerBootstrap;  
    import io.netty.channel.ChannelInitializer;  
    import io.netty.channel.ChannelPipeline;  
    import io.netty.channel.EventLoopGroup;  
    import io.netty.channel.nio.NioEventLoopGroup;  
    import io.netty.channel.socket.SocketChannel;  
    import io.netty.channel.socket.nio.NioServerSocketChannel;  
    import io.netty.handler.codec.LengthFieldBasedFrameDecoder;  
    import io.netty.handler.codec.LengthFieldPrepender;  
    import io.netty.handler.codec.string.StringDecoder;  
    import io.netty.handler.codec.string.StringEncoder;  
    import io.netty.util.CharsetUtil;  
    import util.LogCore;  
      
    public class TcpServer {  
        private static final String IP = "127.0.0.1";  
        private static final int PORT = 9999;  
        /** 用于分配处理业务线程的线程组个数 */  
        protected static final int BIZGROUPSIZE = Runtime.getRuntime().availableProcessors() * 2; // 默认  
        /** 业务出现线程大小 */  
        protected static final int BIZTHREADSIZE = 4;  
        /*
         * NioEventLoopGroup实际上就是个线程池,
         * NioEventLoopGroup在后台启动了n个NioEventLoop来处理Channel事件,
         * 每一个NioEventLoop负责处理m个Channel,
         * NioEventLoopGroup从NioEventLoop数组里挨个取出NioEventLoop来处理Channel
         */  
        private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BIZGROUPSIZE);  
        private static final EventLoopGroup workerGroup = new NioEventLoopGroup(BIZTHREADSIZE);  
      
        protected static void run() throws Exception {  
            ServerBootstrap b = new ServerBootstrap();  
            b.group(bossGroup, workerGroup);  
            b.channel(NioServerSocketChannel.class);  
            b.childHandler(new ChannelInitializer<SocketChannel>() {  
                @Override  
                public void initChannel(SocketChannel ch) throws Exception {  
                    ChannelPipeline pipeline = ch.pipeline();  
                    pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));  
                    pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));  
                    pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));  
                    pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));  
                    pipeline.addLast(new TcpServerHandler());  
                }  
            });  
      
            b.bind(IP, PORT).sync();  
            LogCore.BASE.info("TCP服务器已启动");  
        }  
      
        protected static void shutdown() {  
            workerGroup.shutdownGracefully();  
            bossGroup.shutdownGracefully();  
        }  
      
        public static void main(String[] args) throws Exception {  
            LogCore.BASE.info("启动TCP服务器...");  
            TcpServer.run();  
            // TcpServer.shutdown();  
        }  
    } 


    import io.netty.channel.ChannelHandlerContext;  
    import io.netty.channel.SimpleChannelInboundHandler;  
    import util.LogCore;  
      
    public class TcpServerHandler extends SimpleChannelInboundHandler<Object> {  
      
        @Override  
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {  
            LogCore.BASE.info("SERVER接收到消息:" + msg);  
            ctx.channel().writeAndFlush("server accepted msg:" + msg);  
        }  
      
        @Override  
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
            LogCore.BASE.warn("exceptionCaught!", cause);  
            ctx.close();  
        }  
    } 


    import io.netty.bootstrap.Bootstrap;  
    import io.netty.channel.Channel;  
    import io.netty.channel.ChannelInitializer;  
    import io.netty.channel.ChannelOption;  
    import io.netty.channel.ChannelPipeline;  
    import io.netty.channel.EventLoopGroup;  
    import io.netty.channel.nio.NioEventLoopGroup;  
    import io.netty.channel.socket.nio.NioSocketChannel;  
    import io.netty.handler.codec.LengthFieldBasedFrameDecoder;  
    import io.netty.handler.codec.LengthFieldPrepender;  
    import io.netty.handler.codec.string.StringDecoder;  
    import io.netty.handler.codec.string.StringEncoder;  
    import io.netty.util.CharsetUtil;  
    import util.LogCore;  
      
    public class TcpClient {  
        public static String HOST = "127.0.0.1";  
        public static int PORT = 9999;  
      
        public static Bootstrap bootstrap = getBootstrap();  
        public static Channel channel = getChannel(HOST, PORT);  
      
        /**
         * 初始化Bootstrap
         */  
        public static final Bootstrap getBootstrap() {  
            EventLoopGroup group = new NioEventLoopGroup();  
            Bootstrap b = new Bootstrap();  
            b.group(group).channel(NioSocketChannel.class);  
            b.handler(new ChannelInitializer<Channel>() {  
                @Override  
                protected void initChannel(Channel ch) throws Exception {  
                    ChannelPipeline pipeline = ch.pipeline();  
                    pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));  
                    pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));  
                    pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));  
                    pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));  
                    pipeline.addLast("handler", new TcpClientHandler());  
                }  
            });  
            b.option(ChannelOption.SO_KEEPALIVE, true);  
            return b;  
        }  
      
        public static final Channel getChannel(String host, int port) {  
            Channel channel = null;  
            try {  
                channel = bootstrap.connect(host, port).sync().channel();  
            } catch (Exception e) {  
                LogCore.BASE.error("连接Server(IP{},PORT{})失败", host, port, e);  
                return null;  
            }  
            return channel;  
        }  
      
        public static void sendMsg(String msg) throws Exception {  
            if (channel != null) {  
                channel.writeAndFlush(msg).sync();  
            } else {  
                LogCore.BASE.warn("消息发送失败,连接尚未建立!");  
            }  
        }  
      
        public static void main(String[] args) throws Exception {  
            try {  
                long t0 = System.nanoTime();  
                for (int i = 0; i < 100; i++) {  
                    TcpClient.sendMsg(i + "你好1");  
                }  
                long t1 = System.nanoTime();  
                LogCore.BASE.info("time used:{}", t1 - t0);  
            } catch (Exception e) {  
                LogCore.BASE.error("main err:", e);  
            }  
        }  
    } 


    import io.netty.channel.ChannelHandlerContext;  
    import io.netty.channel.SimpleChannelInboundHandler;  
    import util.LogCore;  
      
    public class TcpClientHandler extends SimpleChannelInboundHandler<Object> {  
      
        @Override  
        protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {  
            LogCore.BASE.info("client接收到服务器返回的消息:" + msg);  
        }  
    } 


猜你喜欢

转载自blog.csdn.net/gaosilingqwer/article/details/78615017