Nginx服务模块开发

本文介绍了如何开发一个基于TCP协议的Nginx服务模块,详细解析了从配置文件增加自定义设置到模块编译进nginx的五个步骤,包括监听端口、初始化参数、处理连接等关键环节。并提供了自定义mypo模块的源码,该模块用于转发客户端数据至指定上流服务器。
摘要由CSDN通过智能技术生成

纵观网上各种关于nginx的模块开发的资料都是基于HTTP的模块开发,这里就整理一篇是基于TCP协议的服务模块开发,并且给出一套自定义服务模块的源码,该模块主要实现的功能是监听某一端口,然后把接收到的客户端数据转发的上流服务器,再把上流服务器的返回数据回传给客户端。模块源码下载地址:https://code.csdn.net/gamer727/nginx_mypo_module
Nginx的服务模块一般都是以四个字母命名的,这里就命名为mypo模块(mypo取“my port”前四个字母)。本模块开发的nginx的版本为1.6.2

根据个人的研究整理,nginx的开发步骤大致归纳以下五步:
第一步,在配置文件中增加自定义配置;
第二步,根据配置文件的内容初始化各种参数;
第三步,开始初始化服务,也就是开始绑定端口,监听端口;
第四步,给各个连接(connection)设置业务处理,这里的业务处理的细节步骤就取决于需求的复杂度了;
第五步,把自定义模块编译进nginx。

第一步,在配置文件nginx.conf中增加自定义配置

mypo {
    server {
        listen 1025;
        upstream 127.0.0.1:1027;

   }

}
配置文件参考

http的,配置文件一般分成三个等级:main、server、location,由于mypo只实现基本的转发功能,所以这里就两个配置,一个listen监听本地端口的,和一个upstream配置上流服务器的。

第二步,根据配置文件的内容初始化各种参数

这里开始进入源码,首先参考http模块新建mypo模块的核心文件:
ngx_mypo_config.h,定义mypo模块的主要结构体和模块标识;
ngx_mypo.c、ngx_mypo.h,mypo模块的入口,调用各种子模块;
ngx_mypo_core_module.c、ngx_mypo_core_module.h,子模块的核心,读取server级别的配置。

首先讲解一下全局配置头文件ngx_mypo_config.h的部分内容:

typedef struct {
    void        **main_conf;
    void        **srv_conf;
    void        **loc_conf;
} ngx_mypo_conf_ctx_t;


typedef struct {
    ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
    ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);

    void       *(*create_main_conf)(ngx_conf_t *cf);
    char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);

    void       *(*create_srv_conf)(ngx_conf_t *cf);
    char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);

    void       *(*create_loc_conf)(ngx_conf_t *cf);
    char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_mypo_module_t;

//定义mypo模块的标识,为了避免数值冲突和统一风格,数值是模块名的ASCII码
#define NGX_MYPO_MODULE           0x4D59504F   /* "MYPO" */

ngx_mypo.c:

//读取完配置文件后,如果匹配到了mypo{}就会调用这个结构体里赋值的
//ngx_mypo_block函数,可以说ngx_mypo_block是mypo的整体框架。
static ngx_command_t  ngx_mypo_commands[] = {

    { ngx_string("mypo"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_mypo_block,
      0,
      0,
      NULL },

      ngx_null_command
};


static ngx_core_module_t  ngx_mypo_module_ctx = {
    ngx_string("mypo"),
    NULL,
    NULL
};

//服务模块入口的结构体,所有的服务模块入口结构体的ngx_module_t.type
//都是设置为NGX_CORE_MODULE的,子模块就是自定义的,如NGX_MYPO_MODULE。
ngx_module_t  ngx_mypo_module = {
    NGX_MODULE_V1,
    &ngx_mypo_module_ctx,                  /* module context */
    ngx_mypo_commands,                     /* module directives */
    NGX_CORE_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

static char *
ngx_mypo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    ngx_uint_t                   mi, m, s;
    ngx_conf_t                   pcf;
    ngx_mypo_module_t           *module;
    ngx_mypo_conf_ctx_t         *ctx;
    ngx_mypo_core_loc_conf_t    *clcf;
    ngx_mypo_core_srv_conf_t   **cscfp;
    ngx_mypo_core_main_conf_t   *cmcf;

    /* the main mypo context */

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mypo_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    *(ngx_mypo_conf_ctx_t **) conf = ctx;


    /* count the number of the mypo modules and set up their indices */

    ngx_mypo_max_module = 0;
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_MYPO_MODULE) {
            continue;
        }

        ngx_modules[m]->ctx_index = ngx_mypo_max_module++;
    }

    /* the mypo main_conf context, it is the same in the all mypo contexts */

    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_mypo_max_module);
    if (ctx->main_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the mypo null srv_conf context, it is used to merge
     * the server{}s' srv_conf's
     */

    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mypo_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the mypo null loc_conf context, it is used to merge
     * the server{}s' loc_conf's
     */

    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mypo_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * create the main_conf's, the null srv_conf's, and the null loc_conf's
     * of the all mypo modules
     */

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_MYPO_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        if (module->create_main_conf) {
            ctx->main_conf[mi] = module->create_main_conf(cf);
            if (ctx->main_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_srv_conf) {
            ctx->srv_conf[mi] = module->create_srv_conf(cf);
            if (ctx->srv_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_loc_conf) {
            ctx->loc_conf[mi] = module->create_loc_conf(cf);
            if (ctx->loc_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }

    pcf = *cf;
    cf->ctx = ctx;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_MYPO_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;

        if (module->preconfiguration) {
            if (module->preconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    /* parse inside the mypo{} block */

    cf->module_type = NGX_MYPO_MODULE;
    cf->cmd_type = NGX_MYPO_MAIN_CONF;
    rv = ngx_conf_parse(cf, NULL);

    if (rv != NGX_CONF_OK) {
        goto failed;
    }

    /*
     * init mypo{} main_conf's, merge the server{}s' srv_conf's
     * and its location{}s' loc_conf's
     */

    cmcf = ctx->main_conf[ngx_mypo_core_module.ctx_index];
    cscfp = cmcf->servers.elts;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_MYPO_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        /* init mypo{} main_conf's */

        if (module->init_main_conf) {
            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
            if (rv != NGX_CONF_OK) {
                goto failed;
            }
        }

        rv = ngx_mypo_merge_servers(cf, cmcf, module, mi);
        if (rv != NGX_CONF_OK) {
            goto failed;
        }
    }


    /* create location trees */
    for (s = 0; s < cmcf->servers.nelts; s++) {

        clcf = cscfp[s]->ctx->loc_conf[ngx_mypo_core_module.ctx_index];

        if (ngx_mypo_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }

        if (ngx_mypo_init_static_location_trees(cf, clcf) != NGX_OK) {
            return NGX_CONF_ERROR;
        }
    }

    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值