Nginx源码分析1--------编写Nginx扩展模块

近日来申请通过CSDN准专家,为了顺利在六个月后升级为认证专家,并对得起这个勋章,我感觉 不能松懈博客的更新频率以及质量了。C/C++ windows下的开发是我相对来说做的比较多的地方,对于Linux下的服务器开发
等等也算是半路出家,恰逢近来在研究分布式存储,涉及到了 Nginx 扩展开发以及配置,查阅了好多的资料发现Nginx配置部署起来相当的容易,但是源代码是真的晦涩难懂,经常会看的我们百思不得其解,所以扩展开发Nginx模块也不是一个轻松的事情,那我就从Nginx扩展模块开始,一步一步剖析Nginx源代码,

~~太暴力了有木有。

参考了下一些开源代码的实现发现,Nginx代码看似天书实际上是有理可依据的,在Nginx下 我们大约可以写三种类型的扩展 ,我只打算写一个简单的http扩展~但是这带领入门足矣。

1、http扩展

如下图所示的扩展  这些扩展是Nginx自带的 下面我打算仿写的就是这一类扩展 形似神似的东西

2、Filter过滤器

这家伙能干的事情可大了~我们可以把我们的Filter挂接到Nginx的Filter上,进行数据流过滤,具体应用在什么地方大家自己考虑去 ,这里不做解释了。

3、负载均衡器

你是否抱怨过 Nginx的 轮询机制  IP_HASH  以及 服务器权重方式 实现的负载均衡达不到想到的效果? 既然Nginx不能满足你的需求 你需要自己满足自己的需求,你可以扩展一个自己的负载

均衡器。

多说无用啊~~~~还是先上代码吧

英文Ubuntu下搜狗出了点问题 Qt下打不出中文了,注释部分写了英文 凑合看吧。英文也不规范

/****************************************************
 * Nginx Extension Module By YDW
 * ********************************************************/
//定义了一堆宏  并且根据预编译选项 区分不同的操作系统加载不同的配置文件
#include </home/usher/Downloads/nginx-1.6.2/src/core/ngx_config.h>
//nginx内核头文件 包含了nginx所需要的基本头文件 以及 定义了部分nginx 结构体的别名
#include </home/usher/Downloads/nginx-1.6.2/src/core/ngx_core.h>
//nginx类型 string  ngx_str_t  作者真够变态的 所有的类型 操作函数 都自己定义了一遍  而且开发扩展nginx 有些时候必须要用
//作者提供的ngx 系列的类型和函数 这个切记
#include </home/usher/Downloads/nginx-1.6.2/src/core/ngx_string.h>
//定义了处理http协议的结构和函数
#include </home/usher/Downloads/nginx-1.6.2/src/http/ngx_http.h>

//define nginx hello_ydw module struct  定义
typedef struct
{
    //nginx style of string
    ngx_str_t output_words;
} ngx_http_hello_ydw_loc_conf_t;

//process  the hello_ydw command
static char* ngx_http_hello_ydw(ngx_conf_t* cf, ngx_command_t* cmd, void* conf);
//allocate memory for hello world command
static void*ngx_http_hello_ydw_create_loc_conf(ngx_conf_t*cf);
//copy hello ydw argument to another place
static char* ngx_http_hello_ydw_merge_loc_conf(ngx_conf_t*cf,void*parent,void *child);

//structure for hello_ydw Command
// Structure for the HelloWorld command
static ngx_command_t ngx_http_hello_ydw_commands[] = {
    {
        ngx_string("hello_ydw"), // The command name
        NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
        ngx_http_hello_ydw, // The command handler  处理命令的函数
        NGX_HTTP_LOC_CONF_OFFSET,
        offsetof(ngx_http_hello_ydw_loc_conf_t, output_words),
        NULL
    },
    ngx_null_command
};

// Structure for the HelloWorld context
static ngx_http_module_t ngx_http_hello_ydw_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ngx_http_hello_ydw_create_loc_conf,
    ngx_http_hello_ydw_merge_loc_conf
};

// Structure for the HelloWorld module, the most important thing
ngx_module_t ngx_http_hello_ydw_module = {
    NGX_MODULE_V1,
    &ngx_http_hello_ydw_module_ctx,
    ngx_http_hello_ydw_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};
//注意这里才是主要的http请求处理函数
static ngx_int_t ngx_http_hello_ydw_handler(ngx_http_request_t* r) {
    ngx_int_t rc;
    ngx_buf_t* b;
    ngx_chain_t out[2];

    ngx_http_hello_ydw_loc_conf_t* hlcf;
    hlcf = ngx_http_get_module_loc_conf(r, ngx_http_hello_ydw_module);

    r->headers_out.content_type.len = sizeof("text/plain") - 1;
    r->headers_out.content_type.data = (u_char*)"text/plain";

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    out[0].buf = b;
    out[0].next = &out[1];

    b->pos = (u_char*)"hello_ydw, ";
    b->last = b->pos + sizeof("hello_ydw, ") - 1;
    b->memory = 1;

    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));

    out[1].buf = b;
    out[1].next = NULL;

    b->pos = hlcf->output_words.data;
    b->last = hlcf->output_words.data + (hlcf->output_words.len);
    b->memory = 1;
    b->last_buf = 1;

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = hlcf->output_words.len + sizeof("hello_ydw, ") - 1;
    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
        return rc;
    }

    return ngx_http_output_filter(r, &out[0]);
}
//这个函数只是在nginx内存池分配了一个 结构

static void* ngx_http_hello_ydw_create_loc_conf(ngx_conf_t* cf) {
    ngx_http_hello_ydw_loc_conf_t* conf;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_hello_ydw_loc_conf_t));
    if (conf == NULL) {
        return NGX_CONF_ERROR;
    }
    conf->output_words.len = 0;
    conf->output_words.data = NULL;

    return conf;
}
//合并父子配置文件
static char* ngx_http_hello_ydw_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child) {
    ngx_http_hello_ydw_loc_conf_t* prev = parent;
    ngx_http_hello_ydw_loc_conf_t* conf = child;
    ngx_conf_merge_str_value(conf->output_words, prev->output_words, "Nginx");
    return NGX_CONF_OK;
}
//处理 hello_ydw命令的函数
static char* ngx_http_hello_ydw(ngx_conf_t* cf, ngx_command_t* cmd, void* conf) {
    ngx_http_core_loc_conf_t* clcf;
    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    clcf->handler = ngx_http_hello_ydw_handler;
    ngx_conf_set_str_slot(cf, cmd, conf);
    return NGX_CONF_OK;
}

代码编写玩了 现在我们来编写编译配置文件 config复制一个开源扩展的格式我们修改下即可 

ngx_addon_name=ngx_http_hello_ydw_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_ydw_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_hello_ydw_module.c"

代码配置文件 写完了 现在我们建立一个 文件夹 ngx_http_hello_ydw_module 来存放 config 和 ngx_http_hello_ydw_module.c结构如下  好了我们的模块就编写好了啊~~~~~

开始编译安装吧我用的是Nginx_1.62 ,我们下载nginx源代码 解压  

依次

./configure --add-module=../nginx_http_ydw_module/ --prefix=/usr/local/nginx2 --conf-path=/etc/nginx2/nginx.conf

make&&make install  

看到如下结构   最后ngx_http_hello_ydw_module.o已经编译完毕 说明我们的扩展编译成功了

等待make install结束安装 。

好了编译安装完nginx 那么我们首先修改Nginx的配置文件 nginx.conf

添加上一行 

location /hello_ydw

{

#处理hello_ydw命令 这个命令我们在代码声明过得哦。

hello_ydw  ExtensionSuccessful;

}

现在启动Nginx

/usr/local/nginx2/sbin/nginx

现在开始测试效果吧   看吧成功了 到了这一步意味着你可以自己写Nginx的扩展程序了哦 

时间: 2025-01-02 03:12:39

Nginx源码分析1--------编写Nginx扩展模块的相关文章

nginx源码分析--nginx模块解析

nginx的模块非常之多,可以认为所有代码都是以模块的形式组织,这包括核心模块和功能模块,针对不同的应用场合,并非所有的功能模块都要被用到,附录A给出的是默认configure(即简单的http服务器应用)下被连接的模块,这里虽说是模块连接,但nginx不会像apache或lighttpd那样在编译时生成so动态库而在程序执行时再进行动态加载,nginx模块源文件会在生成nginx时就直接被编译到其二进制执行文件中,所以如果要选用不同的功能模块,必须对nginx做重新配置和编译.对于功能模块的选

Nginx源码分析:3张图看懂启动及进程工作原理

编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」.   导读:很多工程师及架构师都希望了解及掌握高性能服务器开发,阅读优秀源代码是一种有效的方式,nginx 是业界知名的高性能 Web 服务器实现,如何有效的阅读及理解 nginx?本文用图解的方式帮助大家来更好的阅读及理解 nginx 关键环节的实现.   陈科,十年行业从业经验,曾在浙江电信.阿里巴巴.华为.五八同城任开发工程及架构师等职,目前负责河狸

nginx源码分析--进程间通信机制 &amp; 同步机制

Nginx源码分析-进程间通信机制 从nginx的进程模型可以知道,master进程和worker进程需要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号,master进程主要就是监控.接受外部信号,将有必要的信号传递给worker进程,master进程大部分时间都是阻塞在sigsuspend()函数调用上.Worker进程屏蔽了所有的外部信号,那么Master进程就通过套接字和worker进程通信,worker进程修改全局变量,使得worker进程接受

nginx源码分析--模块分类

ngx-modules Nginx 主要的模块大致可以分为四类: handler – 协同完成客户端请求的处理.产生响应数据.比如模块, ngx_http_rewrite_module, ngx_http_log_module, ngx_http_static_module. filter – 对 handler 产生的响应数据做各种过滤处理.比如模块, ngx_http_not_modified_filter_module, ngx_http_header_filter_module. ups

nginx源码分析--ngx_http_optimize_servers()函数

这个函数做了连部分工作:1)以端口为入口点 将有用的信息存放到hash表内 2)调用ngx_http_init_listening()函数 对端口进行监听 1. 在ngx_http_core_main_conf_t结构体中有一个字段为ports,是一个数组,数组内存放的全是ngx_http_conf_port_t:对于每一个端口信息(ngx_http_conf_port_t),调用 ngx_http_server_names函数,同时也调用ngx_http_init_listening函数,这里

nginx源码分析--从源码看nginx框架总结

nginx源码总结: 1)代码中没有特别绕特别别扭的编码实现,从变量的定义调用函数的实现封装,都非常恰当,比如从函数命名或者变量命名就可以看出来定义的大体意义,函数的基本功能,再好的架构实现在编码习惯差的人实现也会黯然失色,如果透彻理解代码的实现,领悟架构的设计初衷,觉得每块代码就想经过耐心雕琢一样,不仅仅实现了基本的功能给你,为其他人阅读也会提供很好的支持.细致恰当的命名规则就可以看出作者的功力. 2)更好更高的软件性能体现在架构设计上,好的架构会让软件更加稳定.容易维护.便于扩展.从核心模块

nginx源码分析--nginx外部信号 命令参数

nginx命令行参数 不像许多其他软件系统,Nginx 仅有几个命令行参数,完全通过配置文件来配置 -c </path/to/config> 为 Nginx 指定一个配置文件,来代替缺省的. -t 不运行,而仅仅测试配置文件.nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件. -v 显示 nginx 的版本. -V 显示 nginx 的版本,编译器版本和配置参数. nginx控制信号 可以使用信号系统来控制主进程.默认,nginx 将其主进程的 pid 写入到 /u

nginx源码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接

作为一个web服务器,那么肯定是有监听套接字的,这个监听套接字是用于接收HTTP请求的,这个监听套接字的创建是根据配置文件的内容来创建的,在nginx.conf文件中有多少个地址就需要创建多少个监听套接字.这里不说各个结构体的构造 只说大体情况! 1).首先在main函数中调用了ngx_init_cycle()函数,在这个函数的最后调用了ngx_open_listening_sockets函数,这个函数负责将创建的监听套接字进行套接字选项的设置(比如非阻塞.接受发送的缓冲区.绑定.监听处理) 2

nginx源码分析--配置信息的继承&amp;合并

这里只讲述http{}模块下的配置: 在ngx_http_block()函数内(这个函数别调用时在ngx_inti_cycle内的ngx_conf_parse函数,这个函数遇到http命令时 回调ngx_http_block,开启http{}配置块的解读工作),针对每一个http模块,调用init_conf之后,有调用了ngx_http_merge_servers().这是为何! 首先明确几点:一个http{}配置块内可以包含多个server{}配置块,每个server{}配置块可以包含多个lo