首页 > 系统相关 >从零手写实现 nginx-03-nginx 基于 Netty 实现

从零手写实现 nginx-03-nginx 基于 Netty 实现

时间:2024-06-04 09:13:29浏览次数:29  
标签:03 nginxConfig Netty 实现 nginx new 手写

前言

大家好,我是老马。很高兴遇到你。

我们希望实现最简单的 http 服务信息,可以处理静态文件。

如果你想知道 servlet 如何处理的,可以参考我的另一个项目:

手写从零实现简易版 tomcat minicat

netty 相关

如果你对 netty 不是很熟悉,可以读一下

Netty 权威指南-01-BIO 案例

Netty 权威指南-02-NIO 案例

Netty 权威指南-03-AIO 案例

Netty 权威指南-04-为什么选择 Netty?Netty 入门教程

手写 nginx 系列

如果你对 nginx 原理感兴趣,可以阅读:

从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?

从零手写实现 nginx-02-nginx 的核心能力

从零手写实现 nginx-03-nginx 基于 Netty 实现

从零手写实现 nginx-04-基于 netty http 出入参优化处理

从零手写实现 nginx-05-MIME类型(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)

从零手写实现 nginx-06-文件夹自动索引

从零手写实现 nginx-07-大文件下载

从零手写实现 nginx-08-范围查询

从零手写实现 nginx-09-文件压缩

从零手写实现 nginx-10-sendfile 零拷贝

从零手写实现 nginx-11-file+range 合并

从零手写实现 nginx-12-keep-alive 连接复用

从零手写实现 nginx-13-nginx.conf 配置文件介绍

从零手写实现 nginx-14-nginx.conf 和 hocon 格式有关系吗?

从零手写实现 nginx-15-nginx.conf 如何通过 java 解析处理?

从零手写实现 nginx-16-nginx 支持配置多个 server

基本实现

思路

上一节我们实现了基于 serverSocket 的处理监听,那个性能毕竟一般。

这一次我们一起通过 netty 对代码进行改造升级。

核心实现

启动类

INginxServer 接口不变,我们加一个 netty 的实现类。

这里针对 EventLoopGroup 的配置我们暂时使用默认值,后续可以考虑可以让用户自定义。

/**
 * netty 实现
 * 
 * @author 老马啸西风
 * @since 0.2.0
 */
public class NginxServerNetty implements INginxServer {

    private static final Log log = LogFactory.getLog(NginxServerNetty.class);


    private NginxConfig nginxConfig;

    @Override
    public void init(NginxConfig nginxConfig) {
        this.nginxConfig = nginxConfig;
    }

    @Override
    public void start() {
        // 服务器监听的端口号
        String host = InnerNetUtil.getHost();
        int port = nginxConfig.getHttpServerListen();

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //worker 线程池的数量默认为 CPU 核心数的两倍
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new NginxNettyServerHandler(nginxConfig));
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            // Bind and start to accept incoming connections.
            ChannelFuture future = serverBootstrap.bind(port).sync();

            log.info("[Nginx4j] listen on http://{}:{}", host, port);

            // Wait until the server socket is closed.
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("[Nginx4j] start meet ex", e);
            throw new Nginx4jException(e);
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();

            log.info("[Nginx4j] shutdownGracefully", host, port);
        }
    }

}

处理类

核心的处理逻辑都在 NginxNettyServerHandler 这个类。

这里主要做 3 件事

  1. 解析请求类

  2. 根据请求获取对应的内容

  3. 返回响应内容

/**
 * netty 处理类
 * @author 老马啸西风
 * @since 0.2.0
 */
public class NginxNettyServerHandler extends ChannelInboundHandlerAdapter {

    private static final Log logger = LogFactory.getLog(NginxNettyServerHandler.class);

    private final NginxConfig nginxConfig;

    public NginxNettyServerHandler(NginxConfig nginxConfig) {
        this.nginxConfig = nginxConfig;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] bytes = new byte[buf.readableBytes()];
        buf.readBytes(bytes);
        String requestString = new String(bytes, nginxConfig.getCharset());
        logger.info("[Nginx] channelRead requestString={}", requestString);

        // 请求体
        final NginxRequestConvertor requestConvertor = nginxConfig.getNginxRequestConvertor();
        NginxRequestInfoBo nginxRequestInfoBo = requestConvertor.convert(requestString, nginxConfig);

        // 分发
        final NginxRequestDispatch requestDispatch = nginxConfig.getNginxRequestDispatch();
        String respText = requestDispatch.dispatch(nginxRequestInfoBo, nginxConfig);

        // 结果响应
        ByteBuf responseBuf = Unpooled.copiedBuffer(respText.getBytes());
        ctx.writeAndFlush(responseBuf)
                .addListener(ChannelFutureListener.CLOSE); // Close the channel after sending the response
        logger.info("[Nginx] channelRead writeAndFlush DONE");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("[Nginx] exceptionCaught", cause);
        ctx.close();
    }

}

其中请求的解析为对象,便于后续开发中使用。

分发处理只是加了一层抽象,整体实现和上一节类似。

感兴趣可以阅读源码

小结

本节我们使用 netty 大幅度提升一下响应性能。

到这里我们实现了一个简单的 http 服务器,当然这是远远不够的。

后续我们会继续一起实现更多的 nginx 特性。

我是老马,期待与你的下次重逢。

开源地址

为了便于大家学习,已经将 nginx 开源

https://github.com/houbb/nginx4j

标签:03,nginxConfig,Netty,实现,nginx,new,手写
From: https://www.cnblogs.com/houbbBlogs/p/18230088

相关文章

  • Nginx的Location匹配与Rewrite重写
    目录一.Nginx中location与rewrite1.Nginx中常用正则表达式2.location与rewrite的联系和区别二.location概述1.分类2.匹配规则3.优先级4.示例三.rewrite概述1.rewrite功能2.rewrite执行顺序3.跳转实现4.语法格式5.示例5.1.基于域名的跳转5.2.基于旧域名跳转到新......
  • 初中英语优秀作文分析-003My Favorite Movie Type-我最喜欢的电影类型
    PDF格式公众号回复关键字:SHCZYF003记忆树1I’dliketosharemyfavoritemovietypewithyou.翻译我想和你分享我最喜欢的电影类型。简化记忆电影类型句子结构I主语我,would情态动词愿意做某事,like谓语喜欢,toshare宾语分享,myfavoritemovietype......
  • Error: Failure while executing; mpdecimal-2.5.1.catalina.bottle.tar.gz` exited w
    ==>Installingdependenciesfornode:mpdecimal,ca-certificates,[email protected],readline,sqlite,xz,[email protected],brotli,cmake,c-ares,icu4c,libnghttp2andlibuv==>Installingnodedependency:mpdecimalError:Failurewhileexecuting;`/usr/bin/......
  • Nginx Rewrite
    目录1.Nginx正则表达式2.location概述2.1 location匹配规则2.2location优先级3.rewrite概述4.rewrite实例操作4.1基于域名的跳转4.2基于客户端IP访问跳转4.3基于旧域名跳转到新域名后面加目录4.4基于参数匹配的跳转4.5基于目录下所有php结尾的文件跳转4.......
  • python学习笔记-03
    流程控制1.顺序流程代码自上而下的执行。2.选择流程/分支流程根据在某一步的判断有选择的执行相应的逻辑。2.1单分支if语句if条件表达式: 代码 代码 ...2.2双分支if-else语句if条件表达式: 代码 代码 ...else:代码代码...2.3多分支if......
  • 从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?
    前言大家好,我是老马。很高兴遇到你。作为一个java开发者,工作中一直在使用nginx。却发现一直停留在使用层面,无法深入理解。有一天我在想,为什么不能有一个java版本的nginx呢?一者是理解nginx的设计灵魂,再者java开发者用java语言的服务器不是更加自然吗。于是动手开......
  • Netty服务端代码模板
    /***Echoesbackanyreceiveddatafromaclient.*/publicfinalclassEchoServer{staticfinalintPORT=Integer.parseInt(System.getProperty("port","8007"));publicstaticvoidmain(String[]args)throwsException{......
  • 2024-06-03 英语学习纪要
    coincidence第一次自然拼读这个词的时候我的断开方式是coincidence但是现在发现词根是co所以它的含义也就是n.巧合drasticadj.剧烈的,急剧的drasticmeasures严厉的措施drasticchange巨变drasticshortageoffood事物相当短缺副词形式为drasticallyagre......
  • nginx实现网页缓存防篡改
    简介使用网站防篡改对指定的敏感页面设置缓存,缓存后即使源站页面内容被恶意篡改,WAF也会向访问者返回预先缓存好的页面内容,确保用户看到正确的页面。启用 网页防篡改、敏感信息防泄露开关,才能使用该功能。填写精确的要防护的路径,可以防护该路径下的text、html和图片等内容......
  • Nginx设置反向代理
    源码编译安装Nginx参考:https://i.cnblogs.com/posts/edit-done;postId=9010150;isPublished=false设置include因为反向代理主机较多设置include可以模块化各个主机nginx配置文件#sed'/#/d'/usr/local/nginx/conf/nginx.conf|sed'/^$/d'worker_processes1;events{......