netty

1.eventLoop :

在nettry简介中我们可以了解到我们的eventLoop是一个Selector+一个单线程执行器。里面的run方法处理channel上源源不断的io事件(selecctor多路复用 操作系统提供的结构 可以让一个线程监听多个信道,有任务来了就去通知我们的线程来执行)

我们知道eventLoop是用来帮助我们执行IO操作的,当我们的channel被创建好过后,我们会将他他注册进一个eventLoop中,让eventLoop来监听它的IO操作并且进行处理
我们来简单的过一下流程:在这里插入图片描述
在这里插入图片描述

====================================================================================
final ChannelFuture initAndRegister() {//初始化和注册Channel
        Channel channel = null;

        try {
            channel = this.channelFactory.newChannel();//这个是我们初始化ServerBootStrap的时候传入的channel的class信息形成的对象 他就是反射生成对象
            this.init(channel);//可能设计到操作系统的底层操作了 我进不去
        } catch (Throwable var3) {
            if (channel != null) {
                channel.unsafe().closeForcibly();
            }

            return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
        }

        ChannelFuture regFuture = this.config().group().register(channel);//这里就是关键步骤 向我们的eventGroup注册channel 就是将这个信道交给我们的其中一个eventLoop来处理 他会监听这个信道是否有IO操作 并且处理 至于怎么监听 操作系统底层的Selector收到IO会发给我们的
        if (regFuture.cause() != null) {
            if (channel.isRegistered()) {
                channel.close();
            } else {
                channel.unsafe().closeForcibly();
            }
        }

        return regFuture;
}

遇到IO操作它的做法:

//它后面会跳到这个write方法中 
private void write(Object msg, boolean flush, ChannelPromise promise) {
        AbstractChannelHandlerContext next = this.findContextOutbound();//通过当前的ChannelHandlerContext来找到下一个是ChannelOutBountContext 处理输出的
        Object m = this.pipeline.touch(msg, next);
        EventExecutor executor = next.executor();//获取当前的ctx所对应的信道注册在的EventLoop
        //为什么是EventExeccutor 他是他们的公共父类 所有的EventLoop都是它的子类
        if (executor.inEventLoop()) {//判断当前的线程是否是我们的这个EventLoop所对应的线程 如果是就执行
            if (flush) {
                next.invokeWriteAndFlush(m, promise);
            } else {
                next.invokeWrite(m, promise);
            }
        } else {//如果不是当前的线程 我们需要做一些其他的安全处理的操作
            Object task;
            if (flush) {
                task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise);
            } else {
                task = AbstractChannelHandlerContext.WriteTask.newInstance(next, m, promise);
            }

            safeExecute(executor, (Runnable)task, promise, m);
        }

    }

2.ChannelHandler 和 ChannelPipeline

channelHandler是对我们的输入进来的数据进行操作的一个实现接口 , 用户可以通过自定义的实现来帮助我们获取需要的对象,而ChannelPinpeline会将handler包含进来 ,每一个channel都会有一个对应的Pinpeline来帮助它顺着逻辑线来处理我们的流,如图:在这里插入图片描述
我们直接通过信道调用write方法查看它的执行流程:在这里插入图片描述
通过这个我们可以看出 在Channel对象创建的时候我们就已经为他创建了一个ChannelPipeline
在这里插入图片描述
调用它的write方法:
在这里插入图片描述

//构造方法 创建了ChannelPipeline  创建了一个头指针和尾指针
protected DefaultChannelPipeline(Channel channel) {
        this.channel = (Channel)ObjectUtil.checkNotNull(channel, "channel");
        this.succeededFuture = new SucceededChannelFuture(channel, (EventExecutor)null);
        this.voidPromise = new VoidChannelPromise(channel, true);
        this.tail = new DefaultChannelPipeline.TailContext(this);//创建特殊的头部和尾部节点
        this.head = new DefaultChannelPipeline.HeadContext(this);
        this.head.next = this.tail;
        this.tail.prev = this.head;
}
public final ChannelFuture write(Object msg) {
        return this.tail.write(msg);//从尾巴上开始调用write方法
}
public ChannelFuture write(Object msg) {
        return this.write(msg, this.newPromise());//尾和头都是我们创建的特殊节点
}
public ChannelFuture write(Object msg, ChannelPromise promise) {//做完一些校验操作过后调用我们的write方法
        if (msg == null) {
            throw new NullPointerException("msg");
        } else {
            try {
                if (this.isNotValidPromise(promise, true)) {
                    ReferenceCountUtil.release(msg);
                    return promise;
                }
            } catch (RuntimeException var4) {
                ReferenceCountUtil.release(msg);
                throw var4;
            }

            this.write(msg, false, promise);
            return promise;
        }
}
private void write(Object msg, boolean flush, ChannelPromise promise) {
        AbstractChannelHandlerContext next = this.findContextOutbound();//从尾部向前开始寻找可以的输出处理器
        Object m = this.pipeline.touch(msg, next);
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            if (flush) {
                next.invokeWriteAndFlush(m, promise);//执行任务
            } else {
                next.invokeWrite(m, promise);
            }
        } else {
            Object task;
            if (flush) {
                task = AbstractChannelHandlerContext.WriteAndFlushTask.newInstance(next, m, promise);
            } else {
                task = AbstractChannelHandlerContext.WriteTask.newInstance(next, m, promise);
            }

            safeExecute(executor, (Runnable)task, promise, m);
        }
}
private void invokeWriteAndFlush(Object msg, ChannelPromise promise) {
        if (this.invokeHandler()) {//调用我们的自己的handler来帮助我们进行处理
            this.invokeWrite0(msg, promise);
            this.invokeFlush0();
        } else {
            this.writeAndFlush(msg, promise);//直接write
        }

}

原文:https://www.jianshu.com/p/b9f3f6a16911
1.netty使用了NIO,非阻塞的具体在之前的NIO文章介绍了一点NIO。
2.NIO之所以快还有一个原因就是它不会像其他的一样从Socket赋值到java的堆内存中,而是直接由操作系统开辟一个空间直接使用 所以省去了复制的时间。

http的组成:在这里插入图片描述
所以我们不能一个HttpRequest多次处理 最好一次直接处理一个完整的FullHttpRequest

public class HttpServer {
    private final int port;

    public HttpServer(int port) {
        this.port = port;
    }

    public static void main(String[] args) throws Exception {
        new HttpServer(8888).start();
    }

    public void start() throws Exception {
        ServerBootstrap serverBootstrap=new ServerBootstrap();
        NioEventLoopGroup group=new NioEventLoopGroup();
        serverBootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {//我们自定义的处理功能
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        System.out.println(socketChannel);
                        socketChannel.pipeline()
                        //这个decoder是将我们读取到的byte-->Message
                                .addLast("decoder",new HttpRequestDecoder())
                                //将response的 Message-->byte 因为网络通信是0,1字节传输的
                                .addLast("encoder",new HttpResponseEncoder())
                                //HttpObjectAggregator会保证http请求的完整 它会将属于统一Http请求的信息封装起来 再我们的Handler处理时直接处理完整的请求
                                //以免每次处理请求的一部分 512*1024是合并后的一个请求最大的长度
                                .addLast("aggregator",new HttpObjectAggregator(512 * 1024))
                                .addLast("handler",new HttpHandler());
                                //这个是处理我们的返回值 对业务逻辑进行处理
                    }
                })
                .option(ChannelOption.SO_BACKLOG,128)
                .childOption(ChannelOption.SO_KEEPALIVE,Boolean.TRUE);

        serverBootstrap.bind(port).sync();
    }
}

1.HttpRequestDecoder,用于解码request
2.HttpResponseEncoder,用于编码response
3.aggregator,消息聚合器(重要)。为什么能有FullHttpRequest这个东西,就是因为有他,HttpObjectAggregator,如果没有他,就不会有那个消息是FullHttpRequest的那段Channel,同样也不会有FullHttpResponse。
如果我们将z’h
HttpObjectAggregator(512 * 1024)的参数含义是消息合并的数据大小,如此代表聚合的消息内容长度不超过512kb。
4.添加我们自己的处理接口。

public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {//fullHttpRequest泛型代表我们接收的类型只能是一个完整的Http请求
    private AsciiString contentType = HttpHeaderValues.TEXT_PLAIN;


    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception {
        System.out.println("class"+fullHttpRequest.getClass().getName());
        DefaultFullHttpResponse httpResponse=new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer("test".getBytes()));
        //响应头的设置
        HttpHeaders headers = httpResponse.headers();
        headers.add(HttpHeaderNames.CONTENT_TYPE,contentType + "; charset=UTF-8");
        headers.add(HttpHeaderNames.CONTENT_LENGTH,httpResponse.content().readableBytes());
        headers.add(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE);

        channelHandlerContext.write(httpResponse);
    }

	//执行完上面的read方法过后的处理逻辑
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("channelReadComplete");
        super.channelReadComplete(ctx);
        ctx.flush();
    }
	
	//出现异常过后的处理逻辑
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("exceptionCaught");
        if(cause!=null) cause.printStackTrace();
        if(ctx!=null) ctx.close();
    }
}

我们先运行一下含有aggregator(和并一个请求的处理):
运行程序 直接在浏览器访问我们设置的端口:
在这里插入图片描述
可以看到一个请求只执行了一次:
在这里插入图片描述

我们去掉HttpServer中的.addLast("aggregator",new HttpObjectAggregator(512 * 1024))和将HttpHandler 的泛型去掉再次执行:
可以看到一个请求被拆分为了两个来处理:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值