Linux C++通讯架构【四】:框架搭建

框架搭建

  • 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了

你可能感兴趣的:(网络编程,linux,c++,架构)