Nginx 本质上是基于事件驱动的Web服务器,事件 处理框架所要解决的问题就是如何收集、管理、分发事件。
事件主要 以
- 网络事件(TCP网络事件为主 )
- 定时器事件
Nginx 定义一个 核心模块ngx_event_module,参考博客一深入理解Nginx的 模块化 ,全局观,Nginx在启动时会调用ngx_init_cycle方法 解析配置文件时,一旦 在nginx.conf中找到感兴趣的是”events {}”配置项,ngx_event_module模块开始工作了。在 核心模块ngx_event_module中的ngx_event_core_module模块定义了这个模块会使用哪种事件驱动机制以及如何管理 事件。
事件 模块是 一种新的模块类型,nginx_module_t表示Nginx模块接口,而针对每一种 不同类型的模块,都有一个结构体来描述这一类模块的通用接口,这个接口保存在ngx_module_t结构体的 ctx成员中。核心 模块的 通用接口是ngx_core_module_t,事件通用 接口 是 ngx_event_module_t结构 体:
<code><span>typedef</span><span>struct</span> { <span>//位于文件 ngx_event.h</span><span>//事件模块 的名字</span> ngx_str_t *name; <span>//在解析 配置前,这个回调 方法用于创建存储配置选项参数的结构体</span><span>void</span> *(*create_conf)(ngx_cycle_t *cycle); <span>// 在解析配置项完成 之后,init_conf方法会被调用,用以综合处理当前事件模块感兴趣的全部配置项</span><span>char</span> *(*init_conf)(ngx_cycle_t *cycle, <span>void</span> *conf); <span>// 对于事件驱动机制,每个事件模块需要实现10个抽象方法 </span> ngx_event_actions_t actions; } ngx_event_module_t;</code>
ngx_event_module_t
中的actions
成员是定义事件驱动模块的核心方法。
<code><span>typedef</span><span>struct</span> { <span>/* 添加事件方法,它将负责把1个感兴趣 事件添加到操作 系统提供的事件驱动机制 */</span> ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); <span>/*删除事件方法,它将1个已经存在于事件驱动机制中的事件移除 */</span> ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); <span>/*启用 1个 事件,目前事件框架不会调用 这个 方法,大部分事件驱动模块对于该方法的实现都是与上面的add方法完全一致的*/</span> ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); <span>/*禁用1个事件,目前事件框架不会 调用这个方法 ,大部分事件驱动器对于这个方法的实现与上面的del方法完全一致*/</span> ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); <span>/*向事件驱动机制中添加一个新的连接,这意味着连接上的读写事件都添加到事件驱动机制中*/</span> ngx_int_t (*add_conn)(ngx_connection_t *c); <span>/*从事件驱动机制中移除一个连接的读写事件*/</span> ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); <span>/*仅在多线程环境下会被调用,目前Nginx在产品环境下还不会以多线程方式运行*/</span> ngx_int_t (*notify)(ngx_event_handler_pt handler); <span>/*在正常的工作循环中,将调用process_events方法来 处理事件*/</span> ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); <span>/*初始化事件驱动模块的方法*/</span> ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer); <span>// 退出事件驱动模块前调用的方法</span><span>void</span> (*done)(ngx_cycle_t *cycle); } ngx_event_actions_t;</code>
ngx_event_core_module 和9个事件驱动模块都必须ngx_module_t结构体的ctx成员 实现ngx_event_module_t 接口
<code><span>struct</span> ngx_event_s { <span>/*事件相关的对象,通常data指向ngx_connection_t连接对象。开启文件异步I/O 时,它可能会指向*/</span><span>void</span> *data; <span>/* 标志位,标识事件可写,意味着对应的TCP连接可写,也即连接处于发送网络包状态 */</span><span>unsigned</span> write:<span>1</span>; <span>/* 标志位,标识可建立新的连接,一般是在ngx_listening_t对应的读事件中标记 */</span><span>unsigned</span> accept:<span>1</span>; <span>/*检测当前事件是否是过期的,它仅仅是给驱动模块使用的,而事件消费模块可以不用关心 */</span><span>/* used to detect the stale events in kqueue and epoll */</span><span>unsigned</span> instance:<span>1</span>; <span>/* * the event was passed or would be passed to a kernel; * in aio mode - operation was posted. */</span><span>unsigned</span> active:<span>1</span>; <span>unsigned</span> disabled:<span>1</span>; <span>/* the ready event; in aio mode 0 means that no operation can be posted */</span><span>unsigned</span> ready:<span>1</span>; <span>unsigned</span> oneshot:<span>1</span>; <span>/* aio operation is complete */</span><span>unsigned</span> complete:<span>1</span>; <span>unsigned</span> eof:<span>1</span>; <span>unsigned</span> error:<span>1</span>; <span>unsigned</span> timedout:<span>1</span>; <span>unsigned</span> timer_set:<span>1</span>; <span>unsigned</span> delayed:<span>1</span>; <span>unsigned</span> deferred_accept:<span>1</span>; <span>/* the pending eof reported by kqueue, epoll or in aio chain operation */</span><span>unsigned</span> pending_eof:<span>1</span>; <span>unsigned</span> posted:<span>1</span>; <span>unsigned</span> closed:<span>1</span>; <span>/* to test on worker exit */</span><span>unsigned</span> channel:<span>1</span>; <span>unsigned</span> resolver:<span>1</span>; <span>unsigned</span> cancelable:<span>1</span>; <span>#if (NGX_WIN32)</span><span>/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */</span><span>unsigned</span> accept_context_updated:<span>1</span>; <span>#endif</span><span>#if (NGX_HAVE_KQUEUE)</span><span>unsigned</span> kq_vnode:<span>1</span>; <span>/* the pending errno reported by kqueue */</span><span>int</span> kq_errno; <span>#endif</span><span>/* * kqueue only: * accept: number of sockets that wait to be accepted * read: bytes to read when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * write: available space in buffer when event is ready * or lowat when event is set with NGX_LOWAT_EVENT flag * * epoll with EPOLLRDHUP: * accept: 1 if accept many, 0 otherwise * read: 1 if there can be data to read, 0 otherwise * * iocp: TODO * * otherwise: * accept: 1 if accept many, 0 otherwise */</span><span>#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)</span><span>int</span> available; <span>#else</span><span>unsigned</span> available:<span>1</span>; <span>#endif</span> ngx_event_handler_pt handler; <span>#if (NGX_HAVE_IOCP)</span> ngx_event_ovlp_t ovlp; <span>#endif</span> ngx_uint_t index; ngx_log_t *<span>log</span>; ngx_rbtree_node_t timer; <span>/* the posted queue */</span> ngx_queue_t <span>queue</span>; <span>#if 0</span><span>/* the threads support */</span><span>/* * the event thread context, we store it here * if $(CC) does not understand __thread declaration * and pthread_getspecific() is too costly */</span><span>void</span> *thr_ctx; <span>#if (NGX_EVENT_T_PADDING)</span><span>/* event should not cross cache line in SMP */</span> uint32_t padding[NGX_EVENT_T_PADDING]; <span>#endif</span><span>#endif</span> }; <span>#if (NGX_HAVE_FILE_AIO)</span><span>struct</span> ngx_event_aio_s { <span>void</span> *data; ngx_event_handler_pt handler; ngx_file_t *file; <span>#if (NGX_HAVE_AIO_SENDFILE)</span> ssize_t (*preload_handler)(ngx_buf_t *file); <span>#endif</span> ngx_fd_t fd; <span>#if (NGX_HAVE_EVENTFD)</span> int64_t res; <span>#endif</span><span>#if !(NGX_HAVE_EVENTFD) || (NGX_TEST_BUILD_EPOLL)</span> ngx_err_t err; size_t nbytes; <span>#endif</span> ngx_aiocb_t aiocb; ngx_event_t event; }; <span>#endif</span></code>
Nginx的连接
被动连接
这种连接是指 客户端发起的,服务器被动接受的连接
<code><span>//在 文件ngx_connection.h中</span><span>struct</span> ngx_connection_s { <span>/* 连接未使用时,data成员用于充当连接池中空闲链表中的next指针。当连接被使用时,data的意义由使用它的Nginx模块而定。在HTTP模块中,data指向ngx_http_request_t请求*/</span><span>void</span> *data; <span>// 连接对应的读事件 </span> ngx_event_t *read; <span>// 连接对应的写事件 </span> ngx_event_t *write; <span>// 套接字句柄 </span> ngx_socket_t fd; <span>//直接接收网络字符流的方法</span> ngx_recv_pt recv; <span>// 直接发送网络字符流的办法</span> ngx_send_pt send; <span>// 以ngx_chain_t链表为 参数来 接收 网络 字符流的方法 </span> ngx_recv_chain_pt recv_chain; <span>// 以ngx_chain_t链表为 参数来 发送 网络 字符流的方法 </span> ngx_send_chain_pt send_chain; <span>/*这个连接对应的ngx_listening_t监听对象,此连接由listening监听端口的事件建立*/</span> ngx_listening_t *listening; <span>//这个连接上已经发送出去的字节数</span> off_t sent; <span>// 可以记录日志的ngx_log_t对象</span> ngx_log_t *<span>log</span>; <span>/* 内存池。一般在accept一个新连接时,会创建一个 内存池,而在这个 连接结束时会销毁内存池。所有的ngx_connectionn_t结构 体都是预分配,这个内存池的大小将由上面的listening 监听对象中的 pool_size成员决定*/</span> ngx_pool_t *pool; <span>int</span> type; <span>// 连接客户端的sockaddr结构体</span><span>struct</span> sockaddr *sockaddr; <span>// 连接 sockaddr结构体的 长度</span> socklen_t socklen; <span>// 连接客户端字符串形式的IP地址</span> ngx_str_t addr_text; ngx_str_t proxy_protocol_addr; in_port_t proxy_protocol_port; <span>#if (NGX_SSL)</span> ngx_ssl_connection_t *ssl; <span>#endif</span><span>/*本机监听端口 对应 的sockaddr结构 体 ,也就是listening监听对象中的sock addr成员*/</span><span>struct</span> sockaddr *local_sockaddr; socklen_t local_socklen; <span>/*用于接收、缓存客户端 发来的字节流,每个事件消费模块可自由决定从连接池中分配多大空间给 buffer这个 缓存字段*/</span> ngx_buf_t *buffer; ngx_queue_t <span>queue</span>; <span>// 连接使用次数。ngx_connection_t结构体每次建立一条来自客户端的连接,或者主动向后端服务器发起连接时,number都会加1*/</span> ngx_atomic_uint_t number; <span>// 处理 请求次数</span> ngx_uint_t requests; <span>unsigned</span> buffered:<span>8</span>; <span>unsigned</span> log_error:<span>3</span>; <span>/* ngx_connection_log_error_e */</span><span>unsigned</span> timedout:<span>1</span>; <span>unsigned</span> error:<span>1</span>; <span>unsigned</span> destroyed:<span>1</span>; <span>unsigned</span> idle:<span>1</span>; <span>unsigned</span> reusable:<span>1</span>; <span>unsigned</span> close:<span>1</span>; <span>unsigned</span> shared:<span>1</span>; <span>unsigned</span> sendfile:<span>1</span>; <span>unsigned</span> sndlowat:<span>1</span>; <span>unsigned</span> tcp_nodelay:<span>2</span>; <span>/* ngx_connection_tcp_nodelay_e */</span><span>unsigned</span> tcp_nopush:<span>2</span>; <span>/* ngx_connection_tcp_nopush_e */</span><span>unsigned</span> need_last_buf:<span>1</span>; <span>#if (NGX_HAVE_IOCP)</span><span>unsigned</span> accept_context_updated:<span>1</span>; <span>#endif</span><span>#if (NGX_HAVE_AIO_SENDFILE)</span><span>unsigned</span> busy_count:<span>2</span>; <span>#endif</span><span>#if (NGX_THREADS)</span> ngx_thread_task_t *sendfile_task; <span>#endif</span> };</code>
主动连接
作为Web服务器,Nginx也需要向其他服务器发起连接,使用ngx_peer_connection_t
结构体来表示 主动连接,一个待处理连接的许多特性在 被动连接ngx_connection_t中都被定义过,因此ngx_peer_connection_t结构体中引用了ngx_connection_t这个结构体。
<code><span>// 当使用长连接与上游服务器通信时,可通过该方法由连接池获取 一个新的连接</span><span>typedef</span> ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc, <span>void</span> *data); <span>// 当 使用长连接与上游服务器通信时,通过该方法 将使用完毕 的连接释放给连接池</span><span>typedef</span><span>void</span> (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, <span>void</span> *data, ngx_uint_t state); <span>struct</span> ngx_peer_connection_s { <span>/*一个主动连接实际 上也需要ngx_connection_t结构体的大部分成员,并且处于重用的考虑 而定义 了connecion*/</span> ngx_connection_t *connection; <span>// 远端服务器的socketaddr</span><span>struct</span> sockaddr *sockaddr; <span>// sockaddr地址长度</span> socklen_t socklen; <span>// 远端服务器的名称 </span> ngx_str_t *name; <span>// 表示在连接 一个 远端服务器,当前连接出现 异常失败后可以重试的次数,也就是允许的最多失败的次数</span> ngx_uint_t tries; ngx_msec_t start_time; ngx_event_get_peer_pt get; ngx_event_free_peer_pt <span>free</span>; <span>void</span> *data; <span>#if (NGX_SSL)</span> ngx_event_set_peer_session_pt set_session; ngx_event_save_peer_session_pt save_session; <span>#endif</span><span>// 本机地址信息 </span> ngx_addr_t *local; <span>int</span> type; <span>// 套接字的接收缓冲区大小</span><span>int</span> rcvbuf; <span>// 记录日志的ngx_log_t对象</span> ngx_log_t *<span>log</span>; <span>unsigned</span> cached:<span>1</span>; <span>#if (NGX_HAVE_TRANSPARENT_PROXY)</span><span>unsigned</span> transparent:<span>1</span>; <span>#endif</span><span>/* ngx_connection_log_error_e */</span><span>unsigned</span> log_error:<span>2</span>; };</code>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });
以上就介绍了 四:深入Nginx之事件和连接 (之一),包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

使用数据库存储会话的主要优势包括持久性、可扩展性和安全性。1.持久性:即使服务器重启,会话数据也能保持不变。2.可扩展性:适用于分布式系统,确保会话数据在多服务器间同步。3.安全性:数据库提供加密存储,保护敏感信息。

在PHP中实现自定义会话处理可以通过实现SessionHandlerInterface接口来完成。具体步骤包括:1)创建实现SessionHandlerInterface的类,如CustomSessionHandler;2)重写接口中的方法(如open,close,read,write,destroy,gc)来定义会话数据的生命周期和存储方式;3)在PHP脚本中注册自定义会话处理器并启动会话。这样可以将数据存储在MySQL、Redis等介质中,提升性能、安全性和可扩展性。

SessionID是网络应用程序中用来跟踪用户会话状态的机制。1.它是一个随机生成的字符串,用于在用户与服务器之间的多次交互中保持用户的身份信息。2.服务器生成并通过cookie或URL参数发送给客户端,帮助在用户的多次请求中识别和关联这些请求。3.生成通常使用随机算法保证唯一性和不可预测性。4.在实际开发中,可以使用内存数据库如Redis来存储session数据,提升性能和安全性。

在无状态环境如API中管理会话可以通过使用JWT或cookies来实现。1.JWT适合无状态和可扩展性,但大数据时体积大。2.Cookies更传统且易实现,但需谨慎配置以确保安全性。

要保护应用免受与会话相关的XSS攻击,需采取以下措施:1.设置HttpOnly和Secure标志保护会话cookie。2.对所有用户输入进行输出编码。3.实施内容安全策略(CSP)限制脚本来源。通过这些策略,可以有效防护会话相关的XSS攻击,确保用户数据安全。

优化PHP会话性能的方法包括:1.延迟会话启动,2.使用数据库存储会话,3.压缩会话数据,4.管理会话生命周期,5.实现会话共享。这些策略能显着提升应用在高并发环境下的效率。

thesession.gc_maxlifetimesettinginphpdeterminesthelifespanofsessiondata,setInSeconds.1)它'sconfiguredinphp.iniorviaini_set().2)abalanceIsiseededeedeedeedeedeedeedto to to avoidperformance andununununununexpectedLogOgouts.3)

在PHP中,可以使用session_name()函数配置会话名称。具体步骤如下:1.使用session_name()函数设置会话名称,例如session_name("my_session")。2.在设置会话名称后,调用session_start()启动会话。配置会话名称可以避免多应用间的会话数据冲突,并增强安全性,但需注意会话名称的唯一性、安全性、长度和设置时机。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

SublimeText3 Linux新版
SublimeText3 Linux最新版

WebStorm Mac版
好用的JavaScript开发工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),