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.pswp.cn/news/165200.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165200.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165200.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HBuilderX前端軟件社區+Thinkphp后端源碼

HBuilderX前端軟件社區thinkphp后端源碼&#xff0c;搭建好后臺在前端找到 util 這個文件把兩個js文件上面的填上自己的域名&#xff0c;登錄HBuilderX賬號沒有賬號就注冊賬號然后上傳文件即可。打包選擇發行 可以打包app或h5等等 后端設置運行目錄為public(重要)&#xff0c;…

大語言模型——BERT和GPT的那些事兒

前言 自然語言處理是人工智能的一個分支。在自然語言處理領域&#xff0c;有兩個相當著名的大語言模型——BERT和GPT。兩個模型是同一年提出的&#xff0c;那一年BERT以不可抵擋之勢&#xff0c;讓整個人工智能屆為之震動。據說當年BERT的影響力是GPT的十倍以上。而現在&#…

PCIE鏈路訓練-狀態機描述2

Configuration.Lanenum.Accept 如果use_modified_TS1_TS2_Ordered_Set為1&#xff0c;需要注意&#xff1a; &#xff08;1&#xff09;tx需要發送Modified TS1而不是正常的TS1&#xff1b; &#xff08;2&#xff09;rx端必須檢查是否收到Modified TS1&#xff08;注意一開…

第十七章總結

數據庫基礎 SQL語言 1、select 語句 select 語句用于從數據中檢索數據。語法如下&#xff1a; SELECT 搜選字段列表 FROM 數據表名 WHERE 條件表達式 GROUP BY 字段名 HAVING 條件表達式(指定分組的條件) ORDER BY 字段名[ASC|DESC] 2、insert 語句 insert 語句用于向表中插入新…

Ubuntu20.04 install pnpm

npm install -g pnpm referrence link: Installation | pnpmPrerequisiteshttps://pnpm.io/installation

TrustAsia亮相Matter開發者大會,榮獲Matter優秀賦能者獎

11月22日&#xff0c;由CSA&#xff08;連接標準聯盟&#xff09;中國成員組主辦&#xff0c;CSHIA承辦的“Matter中國區開發者大會2023” 于杭州舉行。 會上&#xff0c;連接標準聯盟中國成員組主席宿為民博士、連接標準聯盟亞洲區架構師楊莉女士、CSHIA秘書長|中智盟投資創始…

藍橋杯官網練習題(最長子序列)

題目描述 我們稱一個字符串S 包含字符串 T 是指 T 是 S 的一個子序列&#xff0c;即可以從字符串 S 中抽出若干個字符&#xff0c;它們按原來的順序組合成一個新的字符串與 T 完全一樣。 給定兩個字符串 S 和 T&#xff0c;請問 T 中從第一個字符開始最長連續多少個字…

LangChain的簡單使用介紹

??覺得內容不錯的話&#xff0c;歡迎點贊收藏加關注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后續會繼續輸入更多優質內容?? &#x1f449;有問題歡迎大家加關注私戳或者評論&#xff08;包括但不限于NLP算法相關&#xff0c;linux學習相關&#xff0c;讀研讀博…

idea里面常用插件

這里列出了一系列常用的 IntelliJ IDEA 插件&#xff0c;它們可以提高開發效率、簡化操作&#xff0c;以及幫助進行代碼分析和優化。以下是每個插件的簡要介紹&#xff1a; GenerateAllSetter&#xff1a;生成對象的所有 set 方法和 get 方法&#xff0c;方便對象之間的轉換。該…

微信小程序實現【點擊 滑動 評分 評星(5星)】功能

wxml文件&#xff1a; <view class"wxpl_xing"><view class"manyidu">{{scoreContent}}</view><view><block wx:for{{scoreArray}} wx:for-item"item"><view classstarLen bindtapchangeScore data-sy"{{…

vuex中的常用屬性有哪些?

在 Vuex 中&#xff0c;有一些常用的屬性可以幫助你管理應用程序的狀態。這些屬性包括 state、getters、mutations 和 actions。 state: 用于存儲應用程序的狀態數據&#xff0c;是 Vuex 存儲數據的地方。當應用程序中的多個組件需要共享狀態時&#xff0c;就可以將這些共享的狀…

力扣283:移動零(JAVA)

題目描述: 意思是將所有0移到最后的同時其余非0元素位置仍然不變 如 1 2 0 5 2 0 經過移動零后變為 1 2 5 2 0 0 思路:使用雙指針的思路來寫 fast:從左往右遍歷數組 slow:非零元素最后的一個位置 將數組分為3個區間 [0,slow]為處理好的非0數據,slow永遠指向最后一個非0數據 [s…

Java面向對象第一天

什么是類&#xff1f;什么是對象&#xff1f; 現實生活是由很多很多對象組成的&#xff0c;基于對象抽出了類 對象&#xff1a;軟件中真實存在的單個的個體/東西 類&#xff1a;類型/類別&#xff0c;代表一類個體 類是對象的模板/模子&#xff0c;對象是類的具體的實例 類中…

docker mysql 宿主機掛載配置文件

官方文檔摘錄&#xff08;勿噴&#xff0c;僅供自己筆記&#xff09; 官方文檔如下&#xff1a; The MySQL startup configuration is specified in the file /etc/mysql/my.cnf, and that file in turn includes any files found in the /etc/mysql/conf.d directory that e…

GoLang語言范圍(Range)

目錄 一、在數組、切片上使用‘range’ 二、在映射上使用range 三、在通道上使用range Go語言中的range關鍵字用于迭代數組&#xff08;數組、切片、字符串&#xff09;、映射&#xff08;map&#xff09;、通道&#xff08;channel&#xff09;或者在 for 循環中迭代每一個…

案例022:基于微信小程序的行政復議在線預約系統

文末獲取源碼 開發語言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 數據庫&#xff1a;mysql 5.7 開發軟件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序開發軟件&#xff1a;HBuilder X 小程序…

Django之中間件

引入 1、Django自帶7個中間件&#xff0c;每個中間件都有各自的功能 2、django能夠自定義中間件 3、使用場景&#xff1a; 1. 全局身份校驗 2. 全局用戶權限校驗 3. 全局訪問頻率的校驗 ...... 【1】什么是中間件 Django中間件是一個輕量級、可重用的組件&#xff0c;用于處理…

python運行jackhmmer二進制命令的包裝器類

jackhmmer 是 HMMER 軟件套件中的一個工具&#xff0c;用于進行高敏感度的蛋白質序列比對。HMMER&#xff08;Hidden Markov Model based on profile&#xff09;是一套用于分析蛋白質序列的工具&#xff0c;它使用隱藏馬爾可夫模型&#xff08;HMM&#xff09;來建模蛋白質家族…

nodejs微信小程序+python+PHP -留學信息查詢系統的設計與實現-安卓-計算機畢業設計

目 錄 摘 要 I ABSTRACT II 目 錄 II 第1章 緒論 1 1.1背景及意義 1 1.2 國內外研究概況 1 1.3 研究的內容 1 第2章 相關技術 3 2.1 nodejs簡介 4 2.2 express框架介紹 6 2.4 MySQL數據庫 4 第3章 系統分析 5 3.1 需求分析 5 3.2 系統可行性分析 5 3.2.1技術可行性&#xff1a;…

543. 二叉樹的直徑 --力扣 --JAVA

題目 給你一棵二叉樹的根節點&#xff0c;返回該樹的 直徑 。 二叉樹的 直徑 是指樹中任意兩個節點之間最長路徑的 長度 。這條路徑可能經過也可能不經過根節點 root 。 兩節點之間路徑的 長度 由它們之間邊數表示。 解題思路 最長長度可以理解為左子樹最長路徑加上右子樹最長…