框架搭建
- Makefile
- 设计原则:有多个目录都需要编译,这些目录下都有Makefile文件,但最终只会有一个可执行文件nginx
- makefile:预处理(.i),汇编(.s),编译(.o)阶段会产生多个中间文件,多个.o文件链接成一个可执行文件,makefile定义编译和链接的规则。
- make的原理:去读当前目录的一个makefile文件(文本文件)
- 总的流程:
-
config.mk设置编译目录和模式(debug和release等)
-
根目录makefile 去循环make所有其他目录
-
其他目录都按照common.mk的编译规则去进行编译(都会生成.d依赖文件和.o可执行文件,但app目录还会生成最终的可执行文件nginx,生成在根目录)
-
make clean删除.d .o等中间文件和旧版本。
-
-
项目配置:对Nginx热升级很有作用
- 单例类
-
读取一个配置的单例类(尽量主线程调用)
-
双锁:
-
第一重检查:防止多个线程去争抢锁
-
真正保证单例,如果只有第一重检查,由于加锁是5行汇编指令,并不是原子操作,所以可能多个线程获取锁,然后new多个对象了
-
-
类中类,用来析构对象
-
构造函数私有不用说了
-
私有静态变量=new 自己,公有静态函数返回单例对象。。。有待商榷。。。
-
-
装载配置文件:
-
一行一行地读,(每行最多500字符 char buf)
-
考虑空行、注释行(#)
-
去掉尾巴的换行符、空格等
-
读完一行,配置文件结构体(根据=分割),追加到结构体指针向量中去
-
关闭文件
-
封装读取string和int类型的函数
-
需配置的项:
-
socket连接相关:端口号,ip
-
数据库连接相关:数据库管理用户、密码等
-
编译目录、是否生成调试信息等
-
-
- 单例类
-
内存泄漏检查工具:valgrind: memcheck:
-
设置标题(进程名、服务名、可执行文件名):
-
argc、argv:其中argv[0] 就是标题名 ./nginx,只要把argv[0]改变了,标题(master进程名)就改变了 ==》strcpy(argv[0],"newTitile")
-
问题来了,newTitile比 ./nginx长,就会把后面参数内容覆盖了,而且argv参数后面还有环境变量参数信息。
-
解决方法:
-
先把evriron的数据搬走,让evrinor指向新的内存
-
把argv[1]及其后面的参数用tmp保存起来
-
把新的标题写入argv[0]这块内存,把tmp的内存追加到argv[0]后面
-
-
-
日志打印:
-
ngx_log_stderr(char *fmt,...) 可变参数,fmt可以有多个%s,%d,打印灵活
-
设置日志时区
-
设置日志等级:debug(开发用)、info、Notice、Warm、Err...
-
Main的书写顺序:
-
无伤大雅的,不需要释放的
-
初始化失败,就要直接退出
-
初始化函数
-
-
-
信号,子进程:
-
信号:信号值(常量),信号名(字面量)、信号处理函数(handler)
-
子进程:一般work线程和cpu核数相等(之前解释过了)
-
创建worker子进程:
-
fork产生子进程,分叉
-
子进程分支 switch case pid=0(子进程返回0);其他:父进程分支,直接break就行。
-
子进程设置:是否屏幕信号(默认接收所有信号)、设置进程标题(不要与父进程重复)
-
假设要杀死这一组进程,kill -9 父进程就可以了
-
子进程进入for(;;)循环,休眠或被唤醒
-
-
父进程master在for(;;)里一直循环,接收信号等
-
signsuspend():主进程阻塞在这里,等待一个信号,此时进程休眠,不占用cpu时间。
-
这个操作只适合master(只要接收信号并管理),因为worker除了接收信号,还要处理任务
-
原子操作:假设有10个信号,其中一个信号把其他信号屏蔽,防止终端处理
-
-
write函数思考:
-
write写成功也只是从应用缓存区写到内核缓存区,因为从内核缓存区写到磁盘很慢(和socket的send()思想类似啊,send()也只是发送到发送缓冲区),等内核缓存区的数据满一页(如4K),才写入磁盘
-
问题来了?如果缓存区写入磁盘的时候,断电了,就会导致数据丢失;所以一些重要的数据需采用缓存同步,将缓存和磁盘的数据保持一致(如直接写磁盘)
-
多进程同时写一个文件,如写日志文件,会混乱码?
-
-
-
-
Nginx的master守护进程(理解的还有问题)
-
创建时机:master 先 fork一个子进程,然后这个进程在fork新的子进程前创建守护进程。因为这个守护进程要做为子进程的父亲
-
创建好了,释放原来的master进程,现在的master进程的ppid为1了
-