Netty

2019-10-29  本文已影响0人  特仑苏纯牛乳

1.Netty怎样切换三种经典的i/o模式
BIO 阻塞 排队打饭模式 JDK1.4 之前
NIO 非阻塞 点单等待被叫模式 JDK1.4 java.nio
AIO 异步 包厢模式 JDK1.7 回调
阻塞与非阻塞:是否等待数据就绪
同步与异步:数据就绪后谁来操作的问题 异步由服务方在数据完成后进行回调操作数据
Netty为什么仅保留了对NIO的支持

Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!

Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!

1.1怎么切换
1.2切换原理 泛型 反射 工厂
1.3服务器开发为什么不需要切换客户端对应的socket

什么是reactor及三种版本?


image.png

开发模式:


image.png
Reactor是一种开发模式,模式的核心流程:
注册时间--->监听(扫描)时间是否发生--->事件发生后进行相应的处理
image.png
image.png
image.png
image.png
image.png
image.png

netty如何支持主从reactor模式的?

EchoServer
        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);//main reactor
        EventLoopGroup workerGroup = new NioEventLoopGroup();         //sub  reactor
        ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)               //set main sub reactor
             .channel(NioServerSocketChannel.class)
             .option(ChannelOption.SO_BACKLOG, 100)
             .handler(new LoggingHandler(LogLevel.INFO))
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     //p.addLast(new LoggingHandler(LogLevel.INFO));
                     p.addLast(serverHandler);
                 }
             });

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable
volatile EventLoopGroup group;
public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        super.group(parentGroup);
        ObjectUtil.checkNotNull(childGroup, "childGroup");
        if (this.childGroup != null) {
            throw new IllegalStateException("childGroup set already");
        }
        this.childGroup = childGroup;
        return this;
    }
//绑定main group
ChannelFuture initAndRegister() {
Channel channel = null;
        try {
            channel = channelFactory.newChannel();
            init(channel);
        } catch (Throwable t) {       .... }

        ChannelFuture regFuture = config().group().register(channel);
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }
}


ServerBootStrap
 @Override
        @SuppressWarnings("unchecked")
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            final Channel child = (Channel) msg;

            child.pipeline().addLast(childHandler);

            setChannelOptions(child, childOptions, logger);
            setAttributes(child, childAttrs);

            try {
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

两种socketChannel(ServerSocketChannel、SocketChannel) 绑定到两个不同的group

为什么说netty的main reactor大多并不能用到一个线程组,只能用线程组里的一个?

服务器地址绑定的时候调用一次

 private ChannelFuture doBind(final SocketAddress localAddress) {
        final ChannelFuture regFuture = initAndRegister();
....
}

netty给channel分配NIO event loop的规则是什么?

public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory
    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            return new GenericEventExecutorChooser(executors);
        }
    }

private static boolean isPowerOfTwo(int val) {
        return (val & -val) == val;

因为数字在电脑中是以[补码]的形式存在的
比如
a = 10
仅以8位举例
正数
a 原码 0000 1010 [补码]与原码相等 0000 1010
负数 补码为 它绝对值的[反码]最后+1

    }

        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }

        @Override
        public EventExecutor next() {
            // 递增 取模 取正值
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }

通用模式的NIO实现多路复用器是怎么跨平台的?

JDK

什么是粘包和半包?常用解决方法、Netty对三种常用封帧方式的支持

粘包:一个包发送多个消息。 半包:消息被拆分多个包发送。
粘包的主要原因:发送方每次写入数据小于套接字缓冲区大小;读取数据不够及时
半包:发送方数据大于套接字大小;发送数据大于协议MTU时,必须拆包

根本原因:TCP是一个流式协议,消息没有边界。UDP就没有这个问题。


20191016200816.png image.png

解码的核心工作流程是什么?

channelRead(... ...)

解码中两种数据积累器(cumulator)的区别?

内存复制与组合

三种解码器的常用额外控制参数有哪些?

以上解码器(ByteToMeaageDecoder)主要是为了解决粘包与半包问题,得到一个正确的字节数组;
二次解码器(MessageToMessageDecoder)(序列化与反序列化相关)

keepalive与idle检测

为什么需要keepalive、怎样设计keepalive、为什么还需要应用层keepalive、idle检测是什么、netty如何开启keepalive与idle检测


image.png image.png

为什么需要应用层keepalive


image.png
image.png image.png
image.png
image.png
image.png
上一篇下一篇

猜你喜欢

热点阅读