nginx使用

1.下载

下载gcc         sudo apt-get install build-essential

 下载nginx源码        git clone http://gitlab.0voice.com/2404_vip/nginx.git

sudo apt-get install libpcre3-dev
 sudo apt-get install zlib1g-dev

2.安装

解压后进入文件,

./configure --prefix=/home/zjx/share/nginx --with-http_realip_module --with-http_addition_module --with-http_ssl_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-stream --with-pcre=/home/zjx/share/nginx/pcre-8.41 --with-zlib=/home/zjx/share/nginx/zlib-1.2.11 --with-openssl=/home/zjx/share/nginx/openssl-1.1.1s

make

make install

3.运行

./sbin/nginx -c conf/nginx.conf

进入

192.168.88.130:80        80在nginx.conf找

重启

 配置conf。backend不是关键字

location /后可跟字符用来https://url/字符

可以加权重,负载均衡

反向代理,指服务器ip和端口被代理。

正向代理,指自己的ip被代理,如vpn。

负载均衡,是在反向代理的基础上,选择代理的子服务器

4.模型

通过fork创建子进程,并在子进程中进行epoll,accept等

5.代码

upstream        把数据从浏览器发送到nginx,再到server

无代码

filter        把数据从nginx发送到浏览器

在子进程中操作

几个接口

pool分配内存时可能会因为对齐造成偏差和浪费

  • void *elts:这是一个指向数组元素存储区域的指针。由于类型是 void *,它可以指向任何类型的数据,具体类型由数组的创建者决定。

  • ngx_uint_t nelts:这个字段表示数组中当前实际存储的元素数量。ngx_uint_t 是Nginx中定义的无符号整数类型,通常是一个平台相关的无符号整数。

  • size_t size:这个字段表示数组中单个元素的大小(以字节为单位)。这个值在数组初始化时设置,用于确定每个元素在内存中的存储空间。

  • ngx_uint_t nalloc:这个字段表示数组分配的元素槽位总数。即使某些槽位当前没有存储元素,它们也已经被分配了内存空间。

  • ngx_pool_t *pool:这个字段指向一个内存池(ngx_pool_t),用于管理数组的内存分配。Nginx使用内存池来高效地管理内存,避免频繁的系统调用和内存碎片问题。

  • ngx_list_part_t *last:这是一个指向链表中最后一个部分的指针。ngx_list_part_t 是链表的一个部分(或称为节点),每个部分包含一组元素。通过这个指针,可以快速访问链表的末尾。

  • ngx_list_part_t part:这是链表的第一个部分。它包含了链表的初始元素集合。

  • size_t size:这个字段表示链表中单个元素的大小(以字节为单位)。这个值在链表初始化时设置,用于确定每个元素在内存中的存储空间。

  • ngx_uint_t nalloc:这个字段表示每个链表部分(ngx_list_part_t)中分配的元素槽位总数。即使某些槽位当前没有存储元素,它们也已经被分配了内存空间。

  • ngx_pool_t *pool:这个字段指向一个内存池(ngx_pool_t),用于管理链表的内存分配。Nginx使用内存池来高效地管理内存,避免频繁的系统调用和内存碎片问题。

  • ngx_hash_elt_t **buckets:这是一个指向哈希表桶数组的指针。每个桶(bucket)是一个指向 ngx_hash_elt_t 结构体数组的指针。ngx_hash_elt_t 结构体代表哈希表中的一个元素,包含键和值。哈希表通过键的哈希值来确定元素应该存储在哪个桶中。

  • ngx_uint_t size:这个字段表示哈希表中桶的数量。哈希表的大小(size)决定了哈希冲突的可能性。较大的哈希表大小可以减少冲突,但也会增加内存消耗

  • ngx_rbtree_node_t *root:这是指向红黑树根节点的指针。根节点是红黑树的入口点,所有的操作都从根节点开始。

  • ngx_rbtree_node_t *sentinel:这是指向哨兵节点的指针。在红黑树中,哨兵节点(也称为空节点或叶子节点)用于表示树的边界和结束条件。所有的叶子节点和根节点的父节点都指向这个哨兵节点。

  • ngx_rbtree_insert_pt insert:这是一个函数指针,指向用于插入新节点的函数。红黑树的插入操作需要根据具体的应用场景来定义,因此通过函数指针来指定插入操作的具体实现

  • ngx_queue_t *prev:这是一个指向链表中前一个节点的指针。通过这个指针,可以快速访问链表中当前节点的前一个节点。

  • ngx_queue_t *next:这是一个指向链表中后一个节点的指针。通过这个指针,可以快速访问链表中当前节点的后一个节点。

  • ngx_queue_s 本身不存储数据,它只是一个链表节点的定义。

  • 实际的数据存储在另一个包含 ngx_queue_s 字段的结构体中。

  • 通过将数据节点链接到链表中,可以实现数据的高效管理和访问

makefile

CXX = gcc CXXFLAGS += -g -Wall -Wextra

NGX_ROOT = /home/king/share/nginx/nginx-1.22.1 PCRE_ROOT = /home/king/share/nginx/pcre-8.45

TARGETS = ngx_code TARGETS_C_FILE = $(TARGETS).c

CLEANUP = rm -f $(TARGETS) *.o

all: $(TARGETS)

clean: $(CLEANUP)

CORE_INCS = -I. \ -I$(NGX_ROOT)/src/core \ -I$(NGX_ROOT)/src/event \ -I$(NGX_ROOT)/src/event/modules \ -I$(NGX_ROOT)/src/os/unix \ -I$(NGX_ROOT)/objs \ -I$(PCRE_ROOT) \

NGX_PALLOC = $(NGX_ROOT)/objs/src/core/ngx_palloc.o NGX_STRING = $(NGX_ROOT)/objs/src/core/ngx_string.o NGX_ALLOC = $(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o NGX_ARRAY = $(NGX_ROOT)/objs/src/core/ngx_array.o NGX_HASH = $(NGX_ROOT)/objs/src/core/ngx_hash.o

$(TARGETS): $(TARGETS_C_FILE) $(CXX) $(CXXFLAGS) $(CORE_INCS) $(NGX_PALLOC) $(NGX_STRING) $(NGX_ALLOC) $(NGX_ARRAY) $(NGX_HASH) $^ -o $@

config文件配置,用在add_module中

main_conf代表http下,srv_conf代表server下,loc_conf代表location,conf_falg代表值为on/off的

ngx_conf_set_flag_slot 用cf把cmd的flags解析,并存放在conf中

offsetof指出存储位置

7个NULL对应图中7个函数,这里不加

8个hook也不用,用NGX padding填充

ngx_http_module_t中输入8个回调函数

ngx_http_filter_conf_t *conf =   ngx_pcalloc(cf->pool, sizeof(ngx_http_filter_conf_t));不论location中是否有label,都会分配内存

ngx_conf_merge_value 函数的作用是:

  • 如果 conf->enable 没有被显式设置(即其值为 NGX_CONF_UNSET),则将其设置为 prev->enable 的值。

  • 如果 conf->enable 已经被设置,则保持其当前值。

  • 如果 prev->enable 也没有被设置,则将其设置为默认值 0

ngx_int_t ngx_http_header_filter(ngx_http_request_t *r){

}添加额外内容长度或者其他头部
ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *chain){

}添加具体内容,比如附加广告。需要在conf文件中,添加flags为on和数据

#include <ngx_http.h>
#include <ngx_core.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>



typedef struct{
	int count;
	struct in_addr addr;
}ngx_px_table_t;
#define ENABLE_RBTREE 1
ngx_px_table_t pv_table[256];
char flags = 0;
char *ngx_http_handler_count_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);

ngx_int_t ngx_http_count_handler(ngx_http_request_t *r);
#if ENABLE_RBTREE
static ngx_rbtree_t rbtree;
static ngx_rbtree_t sentinel =nullptr;

#endif	


static ngx_command_t hander_cmds[]={
	{
		ngx_string("zjx"),
		NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
		ngx_http_handler_count_set,
		NGX_HTTP_LOC_CONF_OFFSET,
		0,NULL
	},
	ngx_null_command
};


static ngx_http_module_t hander{
	NULL,ngx_http_count_handler_init,NULL,NULL,NULL,NULL,NULL,NULL,
}

//名字要和conf中一样
ngx_module_t ngx_http_filter_module={
	NGX_MODULE_V1,&ngx_http_filter_module_ctx,ngx_http_filter_module_commands,
	NGX_HTTP_MODULE,
	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING,
	
};

//自定义红黑树查找方法
ngx_rbtree_node_t*
ngx_rbtree_search_counter_value(ngx_rbtree_node_t *temp, ngx_rbtree_t *key,
    ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t  **p;

    for ( ;; ) {

        /*
         * Timer values
         * 1) are spread in small range, usually several minutes,
         * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
         * The comparison takes into account that overflow.
         */

        /*  node->key < temp->key */
#if ENABLE_RBTREE
		if(key < temp->key){
			p = &temp->left;
		}else if(key > temp->key){
			p = &temp->right;
		}else{
			return temp;
		}
#else
        p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
            ? &temp->left : &temp->right;
#endif

        if (*p == sentinel) {
            return NULL;
        }

        temp = *p;
    }

    
}

//自定义红黑树插入方法,temp为树中结点,node为待插入结点
void
ngx_rbtree_insert_counter_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)
{
    ngx_rbtree_node_t  **p;

    for ( ;; ) {

        /*
         * Timer values
         * 1) are spread in small range, usually several minutes,
         * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
         * The comparison takes into account that overflow.
         */

        /*  node->key < temp->key */
#if ENABLE_RBTREE
		if(node->key < temp->key){
			p = &temp->left;
		}else if(node->key > temp->key){
			p = &temp->right;
		}else{
			//由于时间单位为毫秒几乎不会冲突,所以有冲突时结束
			return;
		}
#else
        p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
            ? &temp->left : &temp->right;
#endif

        if (*p == sentinel) {
            break;
        }

        temp = *p;
    }

    *p = node;
    node->parent = temp;
    node->left = sentinel;
    node->right = sentinel;
    ngx_rbt_red(node);
}


//自定义红黑树遍历函数
void ngx_rbtree_travelsal_counter_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,ngx_rbtree_node_t *sentinel, char*html) {

	if (node != sentinel) {
		ngx_rbtree_travelsal_counter_value(temp, node->left,sentinel,html);
		char str[INET_ADDRSTRLEN] = {0};
		char buffer[128] = {0};
		//把pv_table[i].addr从ip结构体转化为16进制,并存储到str中			
		snprintf(buffer,128, "req from: %s, count: %d <br/>",
		inet_ntop(AF_INET, node->key, str, sizeof(str)), node->data);
		//把buffer内容加到html中
		strcat(html, buffer);
		//printf("key:%d, color:%d\n", node->key, node->color,sentinel);
		ngx_rbtree_travelsal_counter_value(temp, node->right,sentinel,html);
	}
}

char *ngx_http_handler_count_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){
	
#if ENABLE_RBTREE
	ngx_rbtree_init(&rbtree, &sentinel, ngx_rbtree_insert_counter_value);
	

#endif
	//获取对应module的conf

	ngx_http_core_loc_conf_t *corecf =  ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

	corecf->handler = ngx_http_count_handler;
	return NGX_CONF_OK;
}

static int ngx_http_encode_page(char *html){
	//固定显示内容
	sprintf(html, "<h1>zjxzjx</h1>");
	sprintf(html, "<h2>")

#if ENABLE_RBTREE
	ngx_rbtree_travelsal_counter_value(&rbtree, rbtree.root,sentinel, html);

#else
	//非固定内容
	for(int i =0;i<256;i++){
		if(pv_table[index].count!=0){
			char str[INET_ADDRSTRLEN] = {0};
			char buffer[128] = {0};
			//把pv_table[i].addr从ip结构体转化为16进制,并存储到str中			
			snprintf(buffer,128, "req from: %s, count: %d <br/>",
			inet_ntop(AF_INET, &pv_table[i].addr, str, sizeof(str)),  pv_table[i].count);
			//把buffer内容加到html中
			strcat(html, buffer);
		}
	}
#endif
	
	strcat(html, "</h2>")
	return 0; 
}


ngx_int_t ngx_http_count_handler(ngx_http_request_t *r){
	//获得对端的ip地址
	struct sockaddr_in *client_addr =	(struct sockaddr_in *)r->connection->sockaddr;

#if ENABLE_RBTREE
	ngx_rbtree_key_t key = client_addr->sin_addr.s_addr;
	ngx_rbtree_node_t*node = ngx_rbtree_search_counter_value(&rbtree, &key,&sentinel);
	if(node){
		node->data++;
	}else{
		node = ngx_palloc(r->pool,sizeof(ngx_rbtree_node_t));
		node->data=1;
		node->key=key;
		ngx_rbtree_insert_counter_value(&rbtree, node, &sentinel);
	}
#else
	
	//ip地址大端存储,向右移位24,只保留最后.后面的内容
	 int index = client_addr->sin_addr.s_addr >>24;
	pv_table[index].count++;
	memcpy(&pv_table[index].addr, &client_addr->sin_addr,sizeof(client_addr->sin_addr));
#endif
	u_char html[1024] = {0};


	ngx_http_encode_page((char*)html);

	//返回状态,正常默认200
	r->headers_out.status = 200;
	//数据状态,为string类型
	ngx_str_set(&r->headers_out.content_type,"text/html");
	//发送头部
	ngx_http_send_header(r);

	//申请body所需内存
	ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
	//设置body内容,用链表保存
	ngx_chain_t out;
	out.buf = b;
	out.next = NULL;
	//body起始位置
	b->pos = html;
	//body结尾位置
	b->last = html + sizeof(html);
	//是否内存有缓存
	b->memory = 1;
	//是否是最后一个buffer
	b->last_buf = 1;
	//发送出去
	return ngx_http_output_body_filter(r, &out);
	
}

//使用一块共享内存,开辟在init
ngx_int_t  ngx_http_count_handler_init(ngx_conf_t *cf){
	ngx_shm_zone_t *shm_zone;
	ngx_str_t name = ngx_string("count_shm");

	shm_zone = ngx_shared_memory_add(cf,  name, 1024*1024, ngx_http_filter_module);

	ngx_slab_alloc(shm_zone, 1024*1024);
	shm_zone->data 
	return NGX_OK;
}

比如

handler        数据从浏览器到nginx,再到浏览器

在count后再增加功能

首先复制并修改config,把name改成新建的c文件名,其他跟着改

第一个流程再nginx -c开始,初始化一系列进程。

第二个流程根据conf文件和代码生成功能,比如

在conf中找到location,并且NGX_CONF_NOARGS说明/后不能有参数。对应内有zjx,则执行set函数

第三个流程是当http请求来的时候的流程

输入这两个,其他默认就行

#include <ngx_http.h>
#include <ngx_core.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>

typedef struct{
	int count;
	struct in_addr addr;
}ngx_px_table_t;

ngx_px_table_t pv_table[256];
char flags = 0;
char *ngx_http_handler_count_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

ngx_int_t ngx_http_count_handler(ngx_http_request_t *r);


static ngx_command_t hander_cmds[]={
	{
		ngx_string("zjx"),
		NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
		ngx_http_handler_count_set,
		NGX_HTTP_LOC_CONF_OFFSET,
		0,NULL
	},
	ngx_null_command
};


static ngx_http_module_t hander{
	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
}

ngx_module_t ngx_http_filter_module={
	NGX_MODULE_V1,&ngx_http_filter_module_ctx,ngx_http_filter_module_commands,
	NGX_HTTP_MODULE,
	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NGX_MODULE_V1_PADDING,
	
};
	
char *ngx_http_handler_count_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){
	//获取对应module的conf
	ngx_http_core_loc_conf_t *corecf =  ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);

	corecf->handler = ngx_http_count_handler;
	return NGX_CONF_OK;
}

static int ngx_http_encode_page(char *html){
	//固定显示内容
	sprintf(html, "<h1>zjxzjx</h1>");
	sprintf(html, "<h2>")

	//非固定内容
	for(int i =0;i<256;i++){
		if(pv_table[index].count!=0){
			char str[INET_ADDRSTRLEN] = {0};
			char buffer[128] = {0};
			//把pv_table[i].addr从ip结构体转化为16进制,并存储到str中			
			snprintf(buffer,128, "req from: %s, count: %d <br/>"),
			inet_ntop(AF_INET, &pv_table[i].addr, str, sizeof(str)), &pv_table[i].count);
			//把buffer内容加到html中
			strcat(html, buffer);
		}
	}

	
	strcat(html, "</h2>")
	return 0; 
}

ngx_int_t ngx_http_count_handler(ngx_http_request_t *r){
	//获得对端的ip地址
	 struct sockaddr_in *client_addr =  (struct sockaddr_in *)r->connection->sockaddr;
	//ip地址大端存储,向右移位24,只保留最后.后面的内容
	 int index = client_addr->sin_addr.s_addr >>24;
	pv_table[index].count++;
	memcpy(&pv_table[index].addr, &client_addr->sin_addr,sizeof(client_addr->sin_addr));

	u_char html[1024] = {0};
	ngx_http_encode_page((char*)html);

	//返回状态,正常默认200
	r->headers_out.status = 200;
	//数据状态,为string类型
	ngx_str_set(&r->headers_out.content_type,"text/html");
	//发送头部
	ngx_http_send_header(r);

	//申请body所需内存
	ngx_buf_t *b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
	//设置body内容,用链表保存
	ngx_chain_t out;
	out.buf = b;
	out.next = NULL;
	//body起始位置
	b->pos = html;
	//body结尾位置
	b->last = html + sizeof(html);
	//是否内存有缓存
	b->memory = 1;
	//是否是最后一个buffer
	b->last_buf = 1;
	//发送出去
	return ngx_http_output_body_filter(r, &out);
	
}

6.命令

strace ./程序名        对调用进行追踪

创建了10个子进程,在发送连接请求后,进程会全部唤醒,并且争夺请求,消耗太大。nginx会给所有子进程加一个共有的锁,需要先争夺锁,然后唤醒epoll wait

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值