Nginx源码分析(1)

Nginx是一个高性能的HTTP服务器,结合Nginx开发从入门到精通一书和Nginx源码学习服务器的高并发处理。

服务器的架构大同小异,而性能的差异主要来自对数据的处理方式上,也即进程模型和事件模型上。一个客户端请求的数据如何进行接受、存储、解析、返回是服务器做的最主要的工作。


最基础的数据结构

C++之所以不被用来写网站是因为,网站的核心是**处理字符串**。而C++的字符串处理实在比较弱,还要不断惦记GC和内存泄漏。

而Nginx首先封装了一下字符串的数据结构和API。定义位于nginx/src/core/nginx_string.h中。

typedef struct {
    size_t      len;
    u_char     *data;
} ngx_str_t;

Nginx中一个字符串被表示为指针data指示首地址+len指示长度的方式,这种方式唯一定位一个字符串。和标准的glibc API\0的方式标识字符串结束不同,它有很多好处。

  • 通过长度表示字符串长度,减少计算字符串长度的步骤
  • 可以重复引用一段字符串内存,减少不必要的内存分配

这样的表示是不是似曾相识?在Redis的sds中有类似的处理。

struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};

再看看它的API,API以宏的方式定义。

#define ngx_string(str)     { sizeof(str) - 1, (u_char *) str }

#define ngx_null_string     { 0, NULL }

#define ngx_str_set(str, text)     (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text

#define ngx_str_null(str)   (str)->len = 0; (str)->data = NULL

第一个宏定义一个nginx的字符串,用法是

int main()
{
    ngx_str_t stringA = ngx_string("Stop");
    printf("len: %d \n", stringA.len);
    printf("address: %p \n", stringA.data);

    char* p = (char*)("HELLO WORLD");
    printf("address: %p \n", p);
    printf("string %s \n", p);
    return 0;
}

这里直接是宏展开,对结构体进行赋值。先生成了一个临时变量
"stop",然后把临时变量的长度和地址赋值给结构体。
ngx_string
ngx_null_string
{,}格式的,而结构体只能在初始化时进行整体赋值,因而API只能用于赋值时初始化。还需要注意
str必须是常量字符串,因为
sizeof是以
\0为结束标志的。

打印结果

len: 4
address: 0x8048530
address: 0x804854d
string HELLO WORLD

参考

http://tengine.taobao.org/book/chapter_02.html

https://github.com/antirez/redis/blob/unstable/src/sds.h

时间: 2024-11-05 06:25:17

Nginx源码分析(1)的相关文章

nginx源码分析--进程间通信机制 & 同步机制

Nginx源码分析-进程间通信机制 从nginx的进程模型可以知道,master进程和worker进程需要通信,nginx中通信的方式有套接字.共享内存.信号.对于master进程,从外部接受信号,master进程主要就是监控.接受外部信号,将有必要的信号传递给worker进程,master进程大部分时间都是阻塞在sigsuspend()函数调用上.Worker进程屏蔽了所有的外部信号,那么Master进程就通过套接字和worker进程通信,worker进程修改全局变量,使得worker进程接受

nginx源码分析--nginx模块解析

nginx的模块非常之多,可以认为所有代码都是以模块的形式组织,这包括核心模块和功能模块,针对不同的应用场合,并非所有的功能模块都要被用到,附录A给出的是默认configure(即简单的http服务器应用)下被连接的模块,这里虽说是模块连接,但nginx不会像apache或lighttpd那样在编译时生成so动态库而在程序执行时再进行动态加载,nginx模块源文件会在生成nginx时就直接被编译到其二进制执行文件中,所以如果要选用不同的功能模块,必须对nginx做重新配置和编译.对于功能模块的选

nginx源码分析--模块分类

ngx-modules Nginx 主要的模块大致可以分为四类: handler – 协同完成客户端请求的处理.产生响应数据.比如模块, ngx_http_rewrite_module, ngx_http_log_module, ngx_http_static_module. filter – 对 handler 产生的响应数据做各种过滤处理.比如模块, ngx_http_not_modified_filter_module, ngx_http_header_filter_module. ups

nginx源码分析--ngx_http_optimize_servers()函数

这个函数做了连部分工作:1)以端口为入口点 将有用的信息存放到hash表内 2)调用ngx_http_init_listening()函数 对端口进行监听 1. 在ngx_http_core_main_conf_t结构体中有一个字段为ports,是一个数组,数组内存放的全是ngx_http_conf_port_t:对于每一个端口信息(ngx_http_conf_port_t),调用 ngx_http_server_names函数,同时也调用ngx_http_init_listening函数,这里

nginx源码分析--从源码看nginx框架总结

nginx源码总结: 1)代码中没有特别绕特别别扭的编码实现,从变量的定义调用函数的实现封装,都非常恰当,比如从函数命名或者变量命名就可以看出来定义的大体意义,函数的基本功能,再好的架构实现在编码习惯差的人实现也会黯然失色,如果透彻理解代码的实现,领悟架构的设计初衷,觉得每块代码就想经过耐心雕琢一样,不仅仅实现了基本的功能给你,为其他人阅读也会提供很好的支持.细致恰当的命名规则就可以看出作者的功力. 2)更好更高的软件性能体现在架构设计上,好的架构会让软件更加稳定.容易维护.便于扩展.从核心模块

nginx源码分析--nginx外部信号 命令参数

nginx命令行参数 不像许多其他软件系统,Nginx 仅有几个命令行参数,完全通过配置文件来配置 -c </path/to/config> 为 Nginx 指定一个配置文件,来代替缺省的. -t 不运行,而仅仅测试配置文件.nginx 将检查配置文件的语法的正确性,并尝试打开配置文件中所引用到的文件. -v 显示 nginx 的版本. -V 显示 nginx 的版本,编译器版本和配置参数. nginx控制信号 可以使用信号系统来控制主进程.默认,nginx 将其主进程的 pid 写入到 /u

nginx源码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接

作为一个web服务器,那么肯定是有监听套接字的,这个监听套接字是用于接收HTTP请求的,这个监听套接字的创建是根据配置文件的内容来创建的,在nginx.conf文件中有多少个地址就需要创建多少个监听套接字.这里不说各个结构体的构造 只说大体情况! 1).首先在main函数中调用了ngx_init_cycle()函数,在这个函数的最后调用了ngx_open_listening_sockets函数,这个函数负责将创建的监听套接字进行套接字选项的设置(比如非阻塞.接受发送的缓冲区.绑定.监听处理) 2

nginx源码分析--配置信息的继承&amp;合并

这里只讲述http{}模块下的配置: 在ngx_http_block()函数内(这个函数别调用时在ngx_inti_cycle内的ngx_conf_parse函数,这个函数遇到http命令时 回调ngx_http_block,开启http{}配置块的解读工作),针对每一个http模块,调用init_conf之后,有调用了ngx_http_merge_servers().这是为何! 首先明确几点:一个http{}配置块内可以包含多个server{}配置块,每个server{}配置块可以包含多个lo

Nginx源码分析:3张图看懂启动及进程工作原理

编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」.   导读:很多工程师及架构师都希望了解及掌握高性能服务器开发,阅读优秀源代码是一种有效的方式,nginx 是业界知名的高性能 Web 服务器实现,如何有效的阅读及理解 nginx?本文用图解的方式帮助大家来更好的阅读及理解 nginx 关键环节的实现.   陈科,十年行业从业经验,曾在浙江电信.阿里巴巴.华为.五八同城任开发工程及架构师等职,目前负责河狸

nginx源码分析--GDB调试

利用gdb[i]调试nginx[ii]和利用gdb调试其它程序没有两样,不过nginx可以是daemon程序,也可以以多进程运行,因此利用gdb调试和平常会有些许不一样.当然,我们可以选择将nginx设置为非daemon模式并以单进程运行,而这需做如下设置即可: daemon off; master_process off; 这是第一种情况: 这种设置下的nginx在gdb下调试很普通,过程可以[iii]是这样: 执行命令: [email protected]:/usr/local/nginx/