Nginx模块开发之http handler实现流量统计(1)

文章目录

  • 一、handler简介
  • 二、Nginx handler模块开发
    • 2.1、示例代码
    • 2.2、编写config文件
    • 2.3、编译模块到Nginx源码中
    • 2.4、修改conf文件
    • 2.5、执行效果
  • 三、Nginx的热更新
  • 总结

一、handler简介

Handler模块就是接受来自客户端的请求并产生输出的模块。
配置文件中使用location指令可以配置content handler模块,当Nginx系统启动的时候,每个handler模块都有一次机会把自己关联到对应的location上。
如果有多个handler模块都关联了同一个location,那么实际上只有一个handler模块真正会起作用。
所以在开发阶段应该避免多个handler模块关联同一个location的情况发生。

handler模块处理的结果通常有三种情况:

  1. 处理成功。
  2. 处理失败:处理的时候发生了错误。
  3. 拒绝处理:这个location的处理就会由默认的handler模块来进行处理。
    例如,当请求一个静态文件的时候,如果关联到这个location上的一个handler模块拒绝处理,就会由默认的ngx_http_static_module模块进行处理,该模块是一个典型的handler模块。

二、Nginx handler模块开发

2.1、示例代码


#include <ngx_config.h>
#include <ngx_http.h>
#include <ngx_core.h>#include <arpa/inet.h>
#include <netinet/in.h>/*
* ip的访问次数存放在一个key-value数据结构里面,ip是key,value是统计的次数
* 可用的数据结构:
* hash
* rbtree
* 最简单的是数组
*/
typedef struct {int count;struct in_addr addr;
}ngx_pv_table;ngx_pv_table pv_table[256] = { 0 }; //这只适合局域网内存储,正在的数据结构最好用rbtree// 重新组织网页 (网页组包)
void ngx_encode_http_page(char *html)
{sprintf(html, "<h1>Hello, NGX handler! I am FLY.</h1>");strcat(html, "<h2>");int i = 0;for (i = 0; i < 256; i++) {if (pv_table[i].count != 0) {char str[INET_ADDRSTRLEN] = { 0 };char buffer[128] = { 0 };sprintf(buffer, "req from : %s, count: %d <br/>",inet_ntop(AF_INET, &pv_table[i].addr, str, sizeof(str)),pv_table[i].count);strcat(html, buffer);}}strcat(html, "</h2>");
}ngx_int_t ngx_http_count_handler(ngx_http_request_t *r)
{// 这里做统计功能// 获取ip地址struct sockaddr_in *cliaddr = (struct sockaddr_in *)r->connection->sockaddr;// 地址和我们看到的是反着的,通过右移得到ip地址的末尾.符号后面那个位数int idx = cliaddr->sin_addr.s_addr >> 24;pv_table[idx].count++;memcpy(&pv_table[idx].addr, &cliaddr->sin_addr, sizeof(cliaddr->sin_addr));// 重新组织网页u_char html[1024] = { 0 };int len = sizeof(html);ngx_encode_http_page((char*)html);/** 发送http响应*/r->headers_out.status = 200;ngx_str_set(&r->headers_out.content_type, "text/html");// 发送http 头ngx_http_send_header(r);// 内存池拿出一个buffer的内存空间ngx_buf_t *b = ngx_palloc(r->pool, sizeof(ngx_buf_t));b->pos = html;b->last = html + len;b->memory = 1;//内存里操作b->last_buf = 1;//最后内存块// 缓冲链ngx_chain_t out;out.buf = b;out.next = NULL;return ngx_http_output_filter(r, &out);}char *ngx_http_handler_count_set(ngx_conf_t *cf,ngx_command_t *cmd,void *conf)
{ngx_http_core_loc_conf_t *ccf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);// 设置handler的入口函数ccf->handler = ngx_http_count_handler;memset(pv_table, 0, sizeof(pv_table));return NGX_OK;
}// conf文件中的每一行都是一个指令指令
ngx_command_t ngx_http_handler_module_cmd[] = {{//命令名称,比如listen,定义了就可以在conf文件中使用,注意不能和其他的起冲突ngx_string("count"),// 指示name命令放的位置在哪里以及可以带多少个参数,NGX_CONF_FLAGE表示开关标志// predix on/offNGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,// 命令解析,可以使用nginx内部的也可以自己实现ngx_http_handler_count_set,//ngx_http_handler_set_slot,NGX_HTTP_LOC_CONF_OFFSET,0,NULL,},ngx_null_command
};// 用来解析对应的conf文件
static ngx_http_module_t ngx_http_handler_module_ctx = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
};// 模块定义
ngx_module_t ngx_http_handler_module = {NGX_MODULE_V1,&ngx_http_handler_module_ctx,ngx_http_handler_module_cmd,// http的ascii值,指示是什么模块NGX_HTTP_MODULE,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING	// 填充};

说明:
1、handler模块必须提供一个真正的处理函数(即上文中的ngx_http_count_handler),这个函数负责对来自客户端请求的真正处理。这个函数的处理,既可以选择自己直接生成内容,也可以选择拒绝处理,由后续的handler去进行处理,或者是选择丢给后续的filter进行处理。
这个处理函数的原型如下:

// r是http的请求,里面包含请求所有的信息
// 该函数处理成功返回NGX_OK,处理发生错误返回NGX_ERROR,拒绝处理(留给后续的handler进行处理)返回NGX_DECLINE。
// 返回NGX_OK也就代表给客户端的响应已经生成好了,否则返回NGX_ERROR就发生错误了。
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);

2.2、编写config文件

创建:

touch config

内容:

ngx_addon_name=ngx_http_handler_module
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_handler_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_handler_module.c"

注意,config文件要和模块的代码在相同目录。

2.3、编译模块到Nginx源码中

(1)配置中添加模块:

./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_addition_module 
--with-http_gzip_static_module --with-http_secure_link_module 
--with-http_stub_status_module --with-stream --with-pcre=/home/fly/workspace/pcre-8.41 
--with-zlib=/home/fly/workspace/zlib-1.2.11 --with-openssl=/home/fly/workspace/openssl-1.1.0g 
--add-module=/mnt/hgfs/sourcecode_learning/ngx_http_handler_module

注意模块路径要正确。出现如下表示成功:

configuring additional modules
adding module in /mnt/hgfs/sourcecode_learning/ngx_http_handler_module+ ngx_http_handler_module was configured
creating objs/Makefile

(2)查看是否添加模块到动态代码中:

cat objs/ngx_modules.c

(3)编译安装:

make
sudo make install

2.4、修改conf文件

conf文件添加count;


worker_processes 4;events {worker_connections 1024;
}http {upstream backend {server 192.168.7.146:8889;server 192.168.7.146:8890;}server {listen 8888;location / {proxy_pass http://backend;}}server {listen 8889;location / {count;}}server {listen 8890;}server {listen 8891;}}

2.5、执行效果

sudo /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/fly.conf 

在网页输入IP和端口,执行效果如下:
在这里插入图片描述
可以看到,返回的网页中多出了访问次数统计。

三、Nginx的热更新

(1)conf文件热更新:通过reload指令进行重新加成conf文件。reload过程中是重新开启新的进程来加载新的conf文件;比如原来有4个进程在运行,加载新的conf文件时就重新开启4个进程来加载新的配置文件。
(2)可执行程序的热更新:编译安装新的nginx,会把原来的nginx重命名为nginx.old,然后调用nginx reload就会更新。

总结

  1. 上述代码虽然实现了IP访问服务器的流量统计;但是,Nginx是多进程的,上述示例代码没有实现统计数在进程间的共享,这回造成其他进程是重新计数的问题。解决这个问题可以使用共享内存的方式在进程间通信。
  2. 上述代码使用了最简单的数据结构:数组。这不是好的决策,可以将其改为红黑树。
  3. nginx的handler模块开发也可以用在黑白名单的处理(比如当判断到同一个ip发送多个无效请求,可以将其加入到黑名单中)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/212173.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

multiset和multimap(map和set的可重复版)

multiset和multimap multisetmultiset的使用 multimapmultimap的使用 这里有讲解map和set的详细使用&#xff1a; C中的map和set使用详解 multiset multiset的文档介绍 翻译&#xff1a; multiset是按照特定顺序存储元素的容器&#xff0c;其中元素是可以重复的。在multiset…

java--权限修饰符

1.什么是权限修饰符 就是是用来限制类中的成员(成员变量、成员方法、构造器、代码块...)能够被访问的范围。 2.权限修饰符有几种&#xff1f;各自的作用是什么&#xff1f; private<缺省<protected<public(范围由小到大)

【小黑嵌入式系统第六课】嵌入式系统软件设计基础——C语言简述、程序涉及规范、多任务程序设计、状态机建模(FSM)、模块化设计、事件触发、时间触发

上一课&#xff1a; 【小黑嵌入式系统第五课】嵌入式系统开发流程——开发工具、交叉开发环境、开发过程(生成&调试&测试)、发展趋势 下一课&#xff1a; 【小黑嵌入式系统第七课】PSoC 5LP 开发套件&#xff08;CY8CKIT-050B &#xff09;——PSoC 5LP主芯片、I/O系统…

设计高手的秘密武器:5款让平面作品更出彩的软件

平面设计是一种迷人而多样化的艺术形式&#xff0c;它结合了颜色、形状、排版和创造力&#xff0c;通过图像和文本传达信息。市场上有各种各样的平面设计软件&#xff0c;选择合适的设计软件是成为优秀设计师的重要一步。为了降低软件成本&#xff0c;大多数设计师会优先使用免…

FreeRTOS的并行与并发思考

FreeRTOS的任务触发是由滴答时钟触发SysTick中断来触发调度器执行或阻塞或挂起和切换任务的。 首先是任务的并发能力&#xff0c;FreeRTOS的任务执行是基于全抢占调度机制&#xff0c;任务优先级按在就绪列表中由高到低排布&#xff0c;系统首先执行最高优先级任务&#xff0c;…

XUbuntu22.04之解决gpg keyserver receive failed no data(一百九十三)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

STM32CubeIDE 创建 / 导入 .c / .h 文件

目录 CubeMX创建工程 项目管理 将CubeMX创建的工程导入到CubeIDE 创建用于演示的ADD.c文件和ADD.h文件 方式一&#xff1a;在IDE的项目浏览器内创建 方式二&#xff1a;在文件窗口处创建 / 从其他地方复制粘贴过来 将ADD.h添加到头文件搜索路径 将ADD.c添加到源文件搜索…

电脑找不到xinput1_3.dll怎么修复,快速处理dll问题的5个方法分享

在使用电脑的过程中&#xff0c;我们常常会遇到一些常见的问题&#xff0c;其中之一就是“电脑缺少xinput1_3.dll”。这个问题可能会影响到我们对电脑的使用体验&#xff0c;甚至导致某些软件无法正常运行。在我遇到这个问题并解决之后&#xff0c;我深刻地体会到了解决问题的重…

redis运维(十七)事务

一 redis事务 事务核心参考 ① 基础概念 1、场景引入核心&#xff1a;通过现象思考原因? 2、事务的概念 3、事务四大特性说明&#xff1a; redis只具备部分特性 重点1&#xff1a; 原子性和一致性 重点2&#xff1a; 隔离性和持久性 ② redis的事务 1、基础铺垫备注&…

王道p150 20.将给定的表达式树转化为等价的中缀表达式(通过括号反应操作符的计算次序)

本题代码如下 void btreetoexp(tree t, char deep) {if (t NULL)return;else if (t->lchild NULL && t->rchild NULL)printf("%c", t->data);//输出操作数&#xff0c;不加括号else {if (deep > 1)printf("(");btreetoexp(t->l…

『 C++类与对象 』多态之单继承与多继承的虚函数表

文章目录 &#x1fae7; 前言&#x1fae7; 查看虚表&#x1fae7; 单继承下的虚函数表&#x1fae7; 多继承下的虚函数表 &#x1fae7; 前言 多态是一种基于继承关系的语法,既然涉及到继承,而继承的方式有多种: 单继承多继承棱形继承棱形虚拟继承 不同的继承方式其虚表的形…

外部网关协议_边界网关协议BGP

一.边界网关协议BGP的基本概念 边界网关协议(Border Gateway Protocol&#xff0c;BGP&#xff09;属于外部网关协议EGP这个类别&#xff0c;用于自治系统AS之间的路由选择协议。由于在不同AS内度量路由的“代价”(距离、带宽、费用等&#xff09;可能不同&#xff0c;因此对于…