本篇文章主要记录说明使用nginx时,开辟一个简单http模块的时序图,还有nginx中封装的数据结构及其处理函数。
1.如何开发一个充满异步调用,无阻塞的http模块?
首先,我们需要把程序嵌如到nginx中(最终变异处的二进制程序nginx要包含我们的代码)。
然后,这个http模块要能介入到处理流程中。
在正式请求处理时,还要可以获取nginx框架定义的数据结构,解析后的用户请求信息
业务执行完毕后,则要考虑发送响应给用户(包括将磁盘中的文件以http包体的形式发送给用户)
我们都是讨论C/C++语言来进行编写,虽然nginx官方不倡导,本文章不讨论各个核心模块如何配合工作。
2.关于http模块的调用。
1.首先nginx是master和多个worker进程的组合,worket进程会在一个for循环语句例反复调用时间模块检测网络事件,即检测到TCP请求(接收到SYN包),将会为它建立TCP连接。
2.成功建立连接后根据nginx.conf文件中的配置会交由http框架处理。
ps:http框架会试图接收完整的HTTP头部,并在接收到完整的http头部后将请求的uri和nginx.conf里的location配置项的匹配来决定如何分发。
3.处理结束后会调用过滤模块,然后根据配置文件决定自己的行为。
时序图:
ps:需要注意HTTP框架到具体http模块间数据流的传递,还有之间的协同,以后会写到。
模块命名为:ngx_http_mytest_module.c
下面进入正题,所以下nginx中封装的数据类型还有数据结构
以下都为linux操作系统下的解释:
1.整形的封装:
typedef intptr_t ngx_int_t; //代表int typedef uintptr_t ngx_uint_t; //代表unsinged int
2.数据结构:
1.字符串
//字符串的封装。其中data不是普通的字符串,很有可能不以‘0’结尾。必须配合len typedef struct{ size_t len; u_char *data; }ngx_str_t; //用于字符串的比较函数,因为未必有0,所以必须用ngx_strncmp比较 #define ngx_strncmp(s1,s2,n) strncmp((const char *)s1,(const char *)s2,n)
2.链表容器:
//这里封装的链表容器使用是很频繁,比如http头部就是使用这个数据结构来存储的。 typedef struct ngx_list_part_s ngx_list_part_t; struct ngx_list_part_s { void *elts;//数组的起始地址 ngx_uint_t nelts; //已经存在多少个元素,必须小于nalloc ngx_list_part_t *next; //下一个地址 } typedef ngx_list_part_s { ngx_list_part_t *last; //链表最后一个元素 ngx_list_part_t part; //链表第一个数组元素 size_t size; //每一个数组元素占用空间大小 ngx_uint_t nalloc; //数组可以存储多少个数据 ngx_pool_t *poll; //nginx内存池的对象。 }ngx_list_t; //下面是封装的ngx_list_t的函数借口 ngx_list_t *ngx_list_create(ngx_pool_t *pool,ngx_uint_t n,size_t size);//创建 //返回创建链表地址。 static ngx_inline ngx_int_t ngx_list_init(ngx_list_t,ngx_pool_t *pool,ngx_uint_t n,size_t size); //初始化 //返回NGX_OK, NGX_ERROR; void *ngx_list_push(ngx_list_t *list);//添加元素、 //遍历链表 ngx_list_part_t *part = &testlist.part; ngx_str_t = part->elts; for(i = 0;;i++) { if(i >= part->nelts) { if(part->next = NULL) break; part = part->next; header = part->elts; i = 0 ; } printf("%*s\n",str[i].len,str[i].data); }
3.key/value (用于存储http头部信息)
typedef struct { ngx_uint_t hash; ngx_str_t key; ngx_str_t value; u_char* lowcase_key; //全是小写的key字符串。 }ngax_table_elt_t;
4.缓冲区的数据结构
typedef struct ngx_buf_s ngx_buf_t; typedef void * ngx_buf_tag_t; struct ngx_buf_s{ u_char *pos; //数据处理的开始位置; u_char *last; //数据处理的结束位置; off_t file_pos; //处理文件的文件开始位置 off_t file_last; //处理文件的文件结束位置 u_char *start; //如果ngx_buf_t用于内存,那么指向这个内存的起始地址 u_char *end; //缓冲区内存的末尾 ngx_buf_tag_t tag; //缓冲区类型 ngx_file_t *file; //引用的文件 ngx_buf_t *shadow; //影子缓冲区,很少用,设计复杂,简单理解为多个指向同一块内存 unsigned temporary:1; //临时内存标志位,1表示这段内存可以修改 unsigned memory:1; //标志位,为1表示数据在内存中且内存不可以修改 unsigned mmap:1; //1表示这顿啊内存用mmap系统调用映射过来的,不可以被修改 unsigned recycled:1; //1表示可以回收 unsigned in_file:1; //1表示这段缓冲区处理的是文件而不是内存 unsigned flush:1; //1表示需要执行flush操作 unsigned sync:1; //是否需要使用同步方式 unsigned last_buf:1; //表示是否为最后一块缓冲区 unsigned last_in_chain:1; //表示是否是ngx_chain_t中的最后一块缓冲区 unsigned last_shadow:1; //是否是最后一个影子缓冲区,与shadow域配合使用。不建议使用 unsigned temp_file:1; //表示当前缓冲去是否是临时文件 }
5.ngx_chain_t(与ngx_buf_t配合使用,存储向用户发送的HTTP包体,结尾设置为null)
typedef struct ngx_chain_s ngx_chain_t; struct ngx_chain_s{ ngx_buf_t *buf; ngx_chain_t *next; }
以上就是nginx的数据结构。