纵观网上各种关于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;
}
}