├── .gitignore ├── CMakeLists.txt ├── README.md ├── README_old.md ├── app ├── CMakeLists.txt └── nginx.cpp ├── code_statistics ├── activity.html ├── arrow-down.gif ├── arrow-none.gif ├── arrow-up.gif ├── authors.html ├── commits_by_author.dat ├── commits_by_author.plot ├── commits_by_author.png ├── commits_by_year.dat ├── commits_by_year.plot ├── commits_by_year.png ├── commits_by_year_month.dat ├── commits_by_year_month.plot ├── commits_by_year_month.png ├── day_of_week.dat ├── day_of_week.plot ├── day_of_week.png ├── domains.dat ├── domains.plot ├── domains.png ├── files.html ├── files_by_date.dat ├── files_by_date.plot ├── files_by_date.png ├── gitstats.cache ├── gitstats.css ├── hour_of_day.dat ├── hour_of_day.plot ├── hour_of_day.png ├── index.html ├── lines.html ├── lines_of_code.dat ├── lines_of_code.plot ├── lines_of_code.png ├── lines_of_code_by_author.dat ├── lines_of_code_by_author.plot ├── lines_of_code_by_author.png ├── month_of_year.dat ├── month_of_year.plot ├── month_of_year.png ├── sortable.js └── tags.html ├── config ├── log4cpp.properties ├── lucia.conf └── mime.types ├── datapoll ├── CMakeLists.txt ├── cia_datapoll.cpp └── cia_datapoll.h ├── headers ├── cia_global.h ├── header.h └── http_parser.h.gch ├── http-parser-master ├── CMakeLists.txt ├── README.md ├── a.out ├── cia_parser.cpp ├── cia_parser.h ├── http_parser.cpp └── http_parser.h ├── logs ├── CMakeLists.txt ├── cia_kernal_func.cpp ├── cia_kernal_func.h ├── cia_log.cpp └── cia_log.h ├── lucia ├── lucia.dSYM └── Contents │ ├── Info.plist │ └── Resources │ └── DWARF │ └── lucia ├── net ├── CMakeLists.txt ├── cia_comm.h ├── cia_response_header.h ├── cia_socket.cpp ├── cia_socket.h ├── cia_socket_accept.cpp ├── cia_socket_http.cpp ├── cia_socket_operator.cpp ├── cia_socket_post.cpp ├── cia_socket_process.cpp ├── cia_socket_request.cpp └── cia_socket_response.cpp ├── operation ├── CMakeLists.txt ├── cia_operation.cpp └── cia_operation.h ├── proc ├── CMakeLists.txt ├── cia_daemon.cpp ├── cia_process_cycle.cpp └── cia_process_events_and_timers.cpp ├── resource ├── git │ ├── Arch.png │ ├── picture.pptx │ └── thundering_herd.jpg └── static │ └── 404.html ├── signal ├── CMakeLists.txt ├── cia_signal.h └── cia_singal.cpp ├── test.cpp ├── threadpoll ├── CMakeLists.txt ├── cia_threadpoll.cpp └── cia_threadpoo.h └── tools ├── CMakeLists.txt ├── cia_conf.cpp ├── cia_conf.h ├── cia_func.cpp ├── cia_func.h ├── cia_setproctitle.cpp └── cia_setproctitle.h /.gitignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .vscode/ 3 | Log/ 4 | exec.dSYM/ 5 | *.o 6 | *.d 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 项目信息 5 | project (lucia) 6 | 7 | # 指定std=11 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | set(CMAKE_CXX_EXTENSIONS OFF) 11 | 12 | # 添加子目录 13 | INCLUDE_DIRECTORIES( headers tools net logs signal threadpoll datapoll operation http-parser-master) 14 | 15 | # TARGET_LINK_LIBRARIES() 16 | subdirs(tools net logs signal threadpoll proc datapoll operation http-parser-master app) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Lucia Architecture 2 | 3 | `Lucia Server`是一个支持Linux和MacOS的轻量级的静态资源服务器。基于`C++11`,`多进程(1个master进程+多个worker进程)+多线程(Thread Pool)`的架构方式,`epoll(LT)+kqueue的reactor模式`的多路复用技术,完成了在HTTP1.1协议下的对静态资源的请求与响应。主要包含以下几个模块: 4 | 5 | ``` 6 | - 读取配置文件模块 7 | - 基于log4cpp的日志模块 8 | - 信号处理模块 9 | - 进程管理模块 10 | - 线程池模块 11 | - 数据池模块 12 | - http解析和响应模块 13 | ``` 14 | 15 | 16 | 17 | - [Demo演示地址](http://icontinua.cn:8011/index.html) :项目的Gitstats。 18 | 19 | - [代码流程 (Real README)](https://github.com/lsummer/LuciaArchitecture/blob/master/README_old.md) 20 | 21 | ## 系统微架构 22 | 23 | ![Atchitecture](https://github.com/lsummer/LuciaArchitecture/raw/master/resource/git/Arch.png) 24 | 25 | ## 开始使用 26 | 27 | Lucia Server 可以运行在`linux`和`macOS`环境下,已在`Ubuntu 18.04.1 LTS`,`Ubuntu 14.04.5 LTS`和`macOS High Sierra v10.13.3`下测试通过。 28 | 29 | #### 下载 30 | 31 | `git clone https://github.com/lsummer/LuciaArchitecture` 32 | 33 | #### 安装库 34 | 35 | [log4cpp](http://log4cpp.sourceforge.net/) 36 | 安装完成后需要将include和lib位置放入到.bashrc中 37 | ``` 38 | # 临时执行 39 | export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/Cellar/log4cpp/1.1.3/include 40 | export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/Cellar/log4cpp/1.1.3/lib 41 | ``` 42 | 43 | #### 运行 44 | 45 | ``` 46 | cd build 47 | cmake .. 48 | make 49 | ./bin/lucia 50 | ``` 51 | 52 | #### 命令 53 | 54 | ``` 55 | # 仅供推荐使用 56 | 57 | # 查看进程信息 58 | MacOS: ps -eo pid,ppid,tty,pgid,stat,comm |grep -E 'PID|lucia|zsh' 59 | Linux: ps -eo pid,ppid,tty,sid,stat,command |grep -E 'PID|lucia' 60 | 61 | # 结束进程 62 | sudo kill -9 -[pgid|sid] 63 | 64 | # 查看日志 65 | tail -f -n100 ./Log/error.log # 系统启动运行日志 66 | tail -f -n100 ./Log/access.log # 业务处理(http请求)日志 67 | 68 | # 追踪进程系统调用 69 | MacOS: sudo dtruss -p [pid] 70 | Linux: sudo strace -p [pid] 71 | 72 | # GDB 真正debug有用的命令 73 | gdb 74 | ``` 75 | 76 | 77 | 78 | #### 配置 79 | 80 | 配置文件地址:`./config`, 主要包含两个配置文件:`log4cpp.properties`和`lucia.conf`,其中`log4cpp.properties`为日志系统的配置文件,`lucia.conf`为服务器启动的相关配置文件。 81 | 82 | - `log4cpp.properties`的编写规则见 [链接](https://www.ibm.com/developerworks/cn/linux/l-log4cpp/index.html),推荐使用默认配置 83 | 84 | - `lucia.conf`的编写规则如下: 85 | 86 | ``` 87 | # // 描述: 配置文件解析说明 88 | # // 1. 以 "#" 开头的行作为注释 89 | # // 2. 以 "[" 开头的行作为注释 90 | # // 3. 以 "{" 开头的行作为注释 91 | # // 4. 以 "}" 开头的行作为注释 92 | # // 5. 每一行前后空格会被忽略 93 | # // 6. 空行会被忽略 94 | # // 7. 参数设置格式为: 设置名=参数 95 | # // 8. 参数行后面的 "#" 之后的作为注释 96 | # // 9. '\#' 代表 # 97 | # // 10. location 开头的表示一个静态资源映射地址 98 | # // 10.1 ~* 执行正则匹配,但不区分大小写 (四元组) location ~* pattern path 99 | # // 10.2 = 执行完全匹配 (四元组) location = pattern path 100 | # // 10.3 / 所有匹配 (三元组) location / path 101 | ``` 102 | 103 | 104 | 105 | ## 备注 106 | 107 | #### 待解决的问题: 108 | 109 | ``` 110 | - 进程重启,datapoll里面的数据可能会丢失掉,所以要有两种重启的方式,暴力重启和温和重启。 111 | - 惊群效应 112 | - 线程资源池的回收再利用需要延迟吗?需要考虑一下 113 | - Http 中的request和response的cookie 114 | ``` 115 | 116 | 117 | 118 | ## 参考文献 119 | - Unix 环境高级编程 (第3版) 120 | - Unix 网络编程卷1:套接字联网API 121 | - [《linux C++通讯架构实战 卷1》 kuangxiang](https://study.163.com/course/courseMain.htm?courseId=1006470001&share=1&shareId=3088415) 良心课程,推荐! 122 | - [kuque学习笔记](http://andrewliu.in/2016/08/14/Kqueue%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/) 123 | - [便利的开发工具-log4cpp快速使用指南](https://www.ibm.com/developerworks/cn/linux/l-log4cpp/index.html) 124 | - [使用gitstats统计本地git代码](https://sealake.net/analyze-your-local-gitrepo-by-gitstats/) 125 | - [深入解析 multipart/form-data](https://www.jianshu.com/p/29e38bcc8a1d) 126 | - [linux 信号列表及分析](https://blog.51cto.com/myunix/1107528) 127 | - [RESTful API 设计指南](http://www.ruanyifeng.com/blog/2014/05/restful_api.html) -------------------------------------------------------------------------------- /README_old.md: -------------------------------------------------------------------------------- 1 | 2 | #### 步骤1.读取配置文件 3 | - 单例模式(double check 但是未加锁,因为配置文件只在main函数开始时执行) 4 | #### 步骤2.环境变量搬家 5 | - 因为argv和environ是处于栈底之上,所以如果要修改进程的名称(即COMM),为了避免修改了environ,必须要将环境变量搬家。 6 | #### 步骤3.日志系统 7 | - 使用了log4cpp 的日志库, 基于 Meyer Singleton的单例模式,log4cpp是线程安全的,并且该库本身所占用内存很少。 8 | - 使用了可变参数的机制,使用vsprintf进行拼接可变参数。[可变参数的使用方式, va_list , va_start, va_end] 9 | #### 步骤4.进程处理信号 10 | - 核心使用函数 sigaction(), sigsuspend(), sigprocmask(); 11 | #### 步骤5.master进程开启worker进程 12 | - fork(), 之后主进程通过sigsuspend()专门等着监听信号,子进程循环执行着 13 | - 注意设置为守护进程: 14 | - (1)调用umask(0); umask是个函数,用来限制(屏蔽)一些文件权限的。 15 | - (2)fork()一个子进程(脱离终端)出来,然后父进程退出( 把终端空出来,不让终端卡住);固定套路 16 | fork()的目的是想成功调用setsid()来建立新会话,目的是 17 | 18 | 子进程有单独的sid;而且子进程也成为了一个新进程组的组长进程;同时,子进程不关联任何终端了; 19 | - (3) 将输入、输出文件描述父重定向到/dev/null;用dup2 20 | - 注意避免子进程被杀掉之后成为僵尸进程,需要父进程(master进程 监听信号 SIG_CHLD, 然后waitpid()) 21 | #### 步骤6.worker进程开始端口监听 22 | socket() -> setsockopt() -> fcntl() -> bind() -> listen() 23 | 设置socket()套接字 -> 设置ipv4,SO_REUSEADDR -> 设置非阻塞 -> 绑定监听端口 -> 监听端口 24 | ip和端口号要进行htonl(),htons()将本机序转化成网络序实现 25 | reactor反应堆模式 26 | macos: 采用kqueue 27 | liunx: 采用epoll 28 | ![惊群效应](./thundering_herd.jpg) 29 | 30 | #### 步骤7.worker进程开启多线程 31 | done 32 | 33 | #### 步骤8.线程池的分配和处理 34 | 注意:所有的Kevent_Node 都要通过free_link进行回收,因为当FD_Node里面还是什么地方的Kevent_node不用的时候,都需要调用free_link->insertNode() 35 | done 36 | 37 | #### 步骤9.worker进程处理业务 38 | 接收数据-done 39 | 发送数据-done 40 | #### 步骤10.解析http报文 41 | 使用[http-parser](https://github.com/nodejs/http-parser): 42 | http://www.voidcn.com/article/p-kbvcufwq-tt.html 43 | - 无依赖性 44 | - 可以处理持久消息(keep-alive) 45 | - 支持解码chunk编码的消息 46 | - 支持Upgrade协议升级(如无例外就是WebSocket) 47 | - 可以防御缓冲区溢出攻击 48 | 用法很简单: 49 | 一个关键函数调用: 50 | 两个关键设置: 51 | 52 | #### 步骤11.静态服务器搭建 53 | - HTTP REQUEST中的GET解析,请求具体的html文件,参考nginx的配置 54 | - lucia.conf 的解析done, 如需增加只需要修改对应的函数【CConfig::ParseLocation】即可 55 | - 目前主要的request的cookie设置还没有解析,对应的response的cookie也没有设置,如果要增加http请求头和设置响应头,只需修改cia_socket_http中的文件即可 56 | 57 | #### 步骤12.解析图片 58 | 59 | #### 备注: 60 | 待解决的问题: 61 | - [] epoll适配linux环境,这个写好就是0.0.1版本发布之日 62 | - [] 进程重启,datapoll里面的数据可能会丢失掉,所以要有两种重启的方式,暴力重启和温和重启。 63 | - [] 惊群效应 64 | - [] 线程资源池的回收再利用需要延迟吗?需要考虑一下 65 | - [] Http 中的request和response的cookie 66 | 67 | 68 | 注意: 69 | - log4cpp 存在内存泄漏,有点坑。 70 | - 内存泄漏验证方式: 71 | - valgrind --tool=memcheck --leak-check=summary --trace-children=yes --show-reachable=yes ./lucia 72 | 73 | 几个常用命令: 74 | 75 | - `ps -eo pid,ppid,tty,pgid,stat,comm |grep -E 'PID|lucia|zsh'` 76 | - ps -eo pid,ppid,tty,sid,stat,command |grep -E 'PID|lucia' 77 | 78 | - `sudo kill -9 -[PGID]` 79 | 80 | - `tail -f -n100 access.log` 81 | 82 | - `sudo dtruss -p [PID]` 追踪子进程使用,但是其实没啥用,除了看惊群效应。因为函数调用全是系统函数,很无语··· 83 | - sudo strace -p 18936 84 | 安装库: 85 | - [log4cpp](http://log4cpp.sourceforge.net/) 86 | 87 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | aux_source_directory(${PROJECT_BINARY_DIR}/lib LIB_SRCS) 8 | 9 | # 换个地方保存生成的目标二进制文件 10 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 11 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 12 | 13 | LINK_DIRECTORIES("${PROJECT_BINARY_DIR}/lib") 14 | 15 | # 指定生成目标 16 | add_executable(lucia ${DIR_SRCS}) 17 | 18 | # message(STATUS "${PROJECT_BINARY_DIR}/lib") 19 | TARGET_LINK_LIBRARIES(lucia log4cpp cia_datapoll cia_net cia_parser cia_signal cia_tools cia_log cia_operation cia_proc cia_threadpoll) 20 | -------------------------------------------------------------------------------- /app/nginx.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "header.h" 7 | #include "cia_conf.h" 8 | #include "cia_setproctitle.h" 9 | #include "cia_log.h" 10 | #include "cia_kernal_func.h" 11 | #include "cia_signal.h" 12 | // #include "cia_socket.h" 13 | // #include "cia_threadpoo.h" 14 | #include "cia_global.h" 15 | using namespace std; 16 | 17 | // 全局变量 18 | int g_environment = 0; // 环境变量的长度 19 | char **g_os_argv; // 命令行参数 20 | char *new_environment = NULL; //新申请的存放环境变量的空间,主要用于释放 21 | int process_type = 0; 22 | 23 | CSocket socket_ctl; 24 | CThreadPoll threadpoll; // 线程池 25 | DataPoll datapoll; // 数据池 26 | 27 | void freesource(){ 28 | // cout<<"释放资源"<load(conf_file_path) || !conf_file_instance->read_mime()){ 85 | cout << "配置文件加载失败,退出!" << endl; 86 | exit(1); 87 | } 88 | // conf_file_instance->test_showAllitem(); 日志文件测试 89 | // ----------- 4. 设置日志,采用log4cpp --------------------- 90 | cia_logs_init(); // 日志文件初始化 91 | LOG_ERR(INFO, "----------重新启动-------------"); 92 | 93 | if(cia_init_signals() < 0){ 94 | exitcode = 1; 95 | goto libexist; 96 | } 97 | 98 | if(socket_ctl.socket_init() == false){ // 设置监听端口 99 | exitcode = 2; 100 | goto libexist; 101 | } 102 | 103 | // 按照守护进程的方式进行执行 104 | if(CConfig::getInstance()->GetIntDefault("Daemon") == 1){ 105 | exitcode = cia_daemon(); 106 | if(exitcode != 0){ 107 | goto libexist; 108 | } 109 | // cout<<"继续happey" < 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

Activity

12 | 22 | 23 |

Weekly activity

24 | 25 |

Last 32 weeks

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
6
3
2
4
12
2
1
3231302928272625242322212019181716151413121110987654321
26 |

Hour of Day

27 | 28 | 29 | 30 |
Hour01234567891011121314151617181920212223
Commits300000000011122110012636
%10.000.000.000.000.000.000.000.000.000.003.333.333.336.676.673.333.330.000.003.336.6720.0010.0020.00
Hour of Day 31 |

Day of Week

32 | 33 |
DayTotal (%)
Mon1 (3.33%)
Tue3 (10.00%)
Wed1 (3.33%)
Thu6 (20.00%)
Fri2 (6.67%)
Sat9 (30.00%)
Sun8 (26.67%)
Day of Week 34 |

Hour of Week

35 | 36 |
Weekday01234567891011121314151617181920212223
Mon1
Tue111
Wed1
Thu11121
Fri11
Sat2214
Sun1142
37 |

Month of Year

38 | 39 |
MonthCommits (%)
10 (0.00 %)
20 (0.00 %)
311 (36.67 %)
419 (63.33 %)
50 (0.00 %)
60 (0.00 %)
70 (0.00 %)
80 (0.00 %)
90 (0.00 %)
100 (0.00 %)
110 (0.00 %)
120 (0.00 %)
Month of Year 40 |

Commits by year/month

41 | 42 |
MonthCommitsLines addedLines removed
2019-041977181167
2019-031136911822
Commits by year/month 43 |

Commits by Year

44 | 45 |
YearCommits (% of all)Lines addedLines removed
201930 (100.00%)114092989
Commits by Year 46 |

Commits by Timezone

47 | 48 |
TimezoneCommits
+080030
-------------------------------------------------------------------------------- /code_statistics/arrow-down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/arrow-down.gif -------------------------------------------------------------------------------- /code_statistics/arrow-none.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/arrow-none.gif -------------------------------------------------------------------------------- /code_statistics/arrow-up.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/arrow-up.gif -------------------------------------------------------------------------------- /code_statistics/authors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

Authors

12 | 22 | 23 |

List of Authors

24 | 25 |
AuthorCommits (%)+ lines- linesFirst commitLast commitAgeActive days# by commits
吕西亚30 (100.00%)1140929892019-03-162019-04-2236 days, 22:39:53171
26 |

Cumulated Added Lines of Code per Author

27 | 28 | Lines of code per Author 29 |

Commits per Author

30 | 31 | Commits per Author 32 |

Author of Month

33 | 34 |
MonthAuthorCommits (%)Next top 5Number of authors
2019-04吕西亚19 (100.00% of 19)1
2019-03吕西亚11 (100.00% of 11)1
35 |

Author of Year

36 | 37 |
YearAuthorCommits (%)Next top 5Number of authors
2019吕西亚30 (100.00% of 30)1
38 |

Commits by Domains

39 | 40 |
DomainsTotal (%)
163.com30 (100.00%)
Commits by Domains -------------------------------------------------------------------------------- /code_statistics/commits_by_author.dat: -------------------------------------------------------------------------------- 1 | 1552750651 1 2 | 1552750740 2 3 | 1552830542 3 4 | 1552830782 4 5 | 1552830816 5 6 | 1552831114 6 7 | 1552963622 7 8 | 1553233085 8 9 | 1553272015 9 10 | 1553704535 10 11 | 1553947684 11 12 | 1554180111 12 13 | 1554388037 13 14 | 1554627538 14 15 | 1554636529 15 16 | 1554796073 16 17 | 1554907976 17 18 | 1554954569 18 19 | 1554959259 19 20 | 1554989912 20 21 | 1554991064 21 22 | 1555072123 22 23 | 1555085433 23 24 | 1555136856 24 25 | 1555136888 25 26 | 1555169004 26 27 | 1555169499 27 28 | 1555860320 28 29 | 1555860583 29 30 | 1555942644 30 31 | -------------------------------------------------------------------------------- /code_statistics/commits_by_author.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set terminal png transparent size 640,480 5 | set output 'commits_by_author.png' 6 | set key left top 7 | set yrange [0:] 8 | set xdata time 9 | set timefmt "%s" 10 | set format x "%Y-%m-%d" 11 | set grid y 12 | set ylabel "Commits" 13 | set xtics rotate 14 | set bmargin 6 15 | plot 'commits_by_author.dat' using 1:2 title "吕西亚" w lines 16 | -------------------------------------------------------------------------------- /code_statistics/commits_by_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/commits_by_author.png -------------------------------------------------------------------------------- /code_statistics/commits_by_year.dat: -------------------------------------------------------------------------------- 1 | 2019 30 2 | -------------------------------------------------------------------------------- /code_statistics/commits_by_year.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'commits_by_year.png' 5 | unset key 6 | set yrange [0:] 7 | set xtics 1 rotate 8 | set grid y 9 | set ylabel "Commits" 10 | set yrange [0:] 11 | plot 'commits_by_year.dat' using 1:2:(0.5) w boxes fs solid 12 | -------------------------------------------------------------------------------- /code_statistics/commits_by_year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/commits_by_year.png -------------------------------------------------------------------------------- /code_statistics/commits_by_year_month.dat: -------------------------------------------------------------------------------- 1 | 2019-03 11 2 | 2019-04 19 3 | -------------------------------------------------------------------------------- /code_statistics/commits_by_year_month.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'commits_by_year_month.png' 5 | unset key 6 | set yrange [0:] 7 | set xdata time 8 | set timefmt "%Y-%m" 9 | set format x "%Y-%m" 10 | set xtics rotate 11 | set bmargin 5 12 | set grid y 13 | set ylabel "Commits" 14 | plot 'commits_by_year_month.dat' using 1:2:(0.5) w boxes fs solid 15 | -------------------------------------------------------------------------------- /code_statistics/commits_by_year_month.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/commits_by_year_month.png -------------------------------------------------------------------------------- /code_statistics/day_of_week.dat: -------------------------------------------------------------------------------- 1 | 1 Mon 1 2 | 2 Tue 3 3 | 3 Wed 1 4 | 4 Thu 6 5 | 5 Fri 2 6 | 6 Sat 9 7 | 7 Sun 8 8 | -------------------------------------------------------------------------------- /code_statistics/day_of_week.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'day_of_week.png' 5 | unset key 6 | set xrange [0.5:7.5] 7 | set yrange [0:] 8 | set xtics 1 9 | set grid y 10 | set ylabel "Commits" 11 | plot 'day_of_week.dat' using 1:3:(0.5):xtic(2) w boxes fs solid 12 | -------------------------------------------------------------------------------- /code_statistics/day_of_week.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/day_of_week.png -------------------------------------------------------------------------------- /code_statistics/domains.dat: -------------------------------------------------------------------------------- 1 | 163.com 1 30 2 | -------------------------------------------------------------------------------- /code_statistics/domains.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'domains.png' 5 | unset key 6 | unset xtics 7 | set yrange [0:] 8 | set grid y 9 | set ylabel "Commits" 10 | plot 'domains.dat' using 2:3:(0.5) with boxes fs solid, '' using 2:3:1 with labels rotate by 45 offset 0,1 11 | -------------------------------------------------------------------------------- /code_statistics/domains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/domains.png -------------------------------------------------------------------------------- /code_statistics/files.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

Files

12 | 22 |
23 |
Total files
114
Total lines
8420
Average file size
36939.08 bytes
24 | 25 |

File count by date

26 | 27 | Files by Date 28 |

Extensions

29 | 30 |
ExtensionFiles (%)Lines (%)Lines/file
14 (12.28%)10315 (122.51%)736
c1 (0.88%)167 (1.98%)167
cache1 (0.88%)26 (0.31%)26
conf1 (0.88%)58 (0.69%)58
cpp24 (21.05%)5290 (62.83%)220
css1 (0.88%)145 (1.72%)145
dat10 (8.77%)138 (1.64%)13
gch1 (0.88%)2219 (26.35%)2219
gif3 (2.63%)6 (0.07%)2
h16 (14.04%)1198 (14.23%)74
html7 (6.14%)234 (2.78%)33
jpeg1 (0.88%)1112 (13.21%)1112
jpg1 (0.88%)913 (10.84%)913
js1 (0.88%)324 (3.85%)324
md3 (2.63%)451 (5.36%)150
mk2 (1.75%)70 (0.83%)35
out2 (1.75%)197 (2.34%)98
plist1 (0.88%)20 (0.24%)20
plot10 (8.77%)127 (1.51%)12
png12 (10.53%)983 (11.67%)81
properties1 (0.88%)16 (0.19%)16
types1 (0.88%)90 (1.07%)90
-------------------------------------------------------------------------------- /code_statistics/files_by_date.dat: -------------------------------------------------------------------------------- 1 | 2019-03-16 29 2 | 2019-03-16 30 3 | 2019-03-17 44 4 | 2019-03-17 45 5 | 2019-03-19 56 6 | 2019-03-22 61 7 | 2019-03-23 74 8 | 2019-03-28 43 9 | 2019-03-30 43 10 | 2019-04-02 52 11 | 2019-04-04 61 12 | 2019-04-07 63 13 | 2019-04-09 64 14 | 2019-04-10 65 15 | 2019-04-11 107 16 | 2019-04-11 109 17 | 2019-04-11 65 18 | 2019-04-12 109 19 | 2019-04-13 109 20 | 2019-04-13 111 21 | 2019-04-21 113 22 | 2019-04-22 114 23 | -------------------------------------------------------------------------------- /code_statistics/files_by_date.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'files_by_date.png' 5 | unset key 6 | set yrange [0:] 7 | set xdata time 8 | set timefmt "%Y-%m-%d" 9 | set format x "%Y-%m-%d" 10 | set grid y 11 | set ylabel "Files" 12 | set xtics rotate 13 | set ytics autofreq 14 | set bmargin 6 15 | plot 'files_by_date.dat' using 1:2 w steps 16 | -------------------------------------------------------------------------------- /code_statistics/files_by_date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/files_by_date.png -------------------------------------------------------------------------------- /code_statistics/gitstats.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/gitstats.cache -------------------------------------------------------------------------------- /code_statistics/gitstats.css: -------------------------------------------------------------------------------- 1 | /** 2 | * GitStats - default style 3 | */ 4 | body { 5 | color: black; 6 | background-color: #dfd; 7 | } 8 | 9 | dt { 10 | font-weight: bold; 11 | float: left; 12 | margin-right: 1em; 13 | } 14 | 15 | dt:after { 16 | content: ': '; 17 | } 18 | 19 | dd { 20 | display: block; 21 | clear: left; 22 | } 23 | 24 | table { 25 | border: 1px solid black; 26 | border-collapse: collapse; 27 | font-size: 80%; 28 | margin-bottom: 1em; 29 | } 30 | 31 | table.noborders { 32 | border: none; 33 | } 34 | 35 | table.noborders td { 36 | border: none; 37 | } 38 | 39 | .vtable { 40 | float: right; 41 | clear: both; 42 | } 43 | 44 | table.tags td { 45 | vertical-align: top; 46 | } 47 | 48 | td { 49 | background-color: white; 50 | } 51 | 52 | th { 53 | background-color: #ddf; 54 | } 55 | 56 | th a { 57 | text-decoration: none; 58 | } 59 | 60 | tr:hover { 61 | background-color: #ddf; 62 | } 63 | 64 | td { 65 | border: 1px solid black; 66 | padding: 0.2em; 67 | padding-left: 0.3em; 68 | padding-right: 0.2em; 69 | } 70 | 71 | /* Navigation bar; tabbed style */ 72 | .nav { 73 | border-bottom: 1px solid black; 74 | padding: 0.3em; 75 | } 76 | 77 | .nav ul { 78 | list-style-type: none; 79 | display: inline; 80 | margin: 0; 81 | padding: 0; 82 | } 83 | 84 | .nav li { 85 | display: inline; 86 | } 87 | 88 | .nav li a { 89 | padding: 0.3em; 90 | text-decoration: none; 91 | color: black; 92 | border: 1px solid black; 93 | margin: 0.5em; 94 | background-color: #ddf; 95 | } 96 | 97 | .nav li a:hover { 98 | background-color: #ddd; 99 | border-bottom: 1px solid #ddf; 100 | } 101 | 102 | img { 103 | border: 1px solid black; 104 | padding: 0.5em; 105 | background-color: white; 106 | } 107 | 108 | th img { 109 | border: 0px; 110 | padding: 0px; 111 | background-color: #ddf; 112 | } 113 | 114 | h1 a, h2 a { 115 | color: black; 116 | text-decoration: none; 117 | } 118 | 119 | h1:hover a:after, 120 | h2:hover a:after { 121 | content: '¶'; 122 | color: #555; 123 | } 124 | 125 | h1 { 126 | font-size: x-large; 127 | } 128 | 129 | h2 { 130 | background-color: #564; 131 | border: 1px solid black; 132 | padding-left: 0.5em; 133 | padding-right: 0.5em; 134 | color: white; 135 | font-size: large; 136 | clear: both; 137 | } 138 | 139 | h2 a { 140 | color: white; 141 | } 142 | 143 | .moreauthors { 144 | font-size: 80%; 145 | } 146 | -------------------------------------------------------------------------------- /code_statistics/hour_of_day.dat: -------------------------------------------------------------------------------- 1 | 1 3 2 | 2 0 3 | 3 0 4 | 4 0 5 | 5 0 6 | 6 0 7 | 7 0 8 | 8 0 9 | 9 0 10 | 10 0 11 | 11 1 12 | 12 1 13 | 13 1 14 | 14 2 15 | 15 2 16 | 16 1 17 | 17 1 18 | 18 0 19 | 19 0 20 | 20 1 21 | 21 2 22 | 22 6 23 | 23 3 24 | 24 6 25 | -------------------------------------------------------------------------------- /code_statistics/hour_of_day.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'hour_of_day.png' 5 | unset key 6 | set xrange [0.5:24.5] 7 | set yrange [0:] 8 | set xtics 4 9 | set grid y 10 | set ylabel "Commits" 11 | plot 'hour_of_day.dat' using 1:2:(0.5) w boxes fs solid 12 | -------------------------------------------------------------------------------- /code_statistics/hour_of_day.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/hour_of_day.png -------------------------------------------------------------------------------- /code_statistics/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

GitStats - mynginx

12 | 22 |
Project name
mynginx
Generated
2019-04-22 22:19:06 (in 1 seconds)
Generator
GitStats (version 55c5c28), git version 2.15.2 (Apple Git-101.1), gnuplot 5.2 patchlevel 6
Report Period
2019-03-16 23:37:31 to 2019-04-22 22:17:24
Age
38 days, 17 active days (44.74%)
Total Files
114
Total Lines of Code
8420 (11409 added, 2989 removed)
Total Commits
30 (average 1.8 commits per active day, 0.8 per all days)
Authors
1 (average 30.0 commits per author)
23 | -------------------------------------------------------------------------------- /code_statistics/lines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

Lines

12 | 22 |
23 |
Total lines
8420
24 | 25 |

Lines of Code

26 | 27 | Lines of Code -------------------------------------------------------------------------------- /code_statistics/lines_of_code.dat: -------------------------------------------------------------------------------- 1 | 1552750651 672 2 | 1552750740 672 3 | 1552830542 1282 4 | 1552830782 1282 5 | 1552830816 1282 6 | 1552831114 1289 7 | 1552963622 1553 8 | 1553233085 1791 9 | 1553272015 2438 10 | 1553704535 1808 11 | 1553947684 1869 12 | 1554180111 2043 13 | 1554388037 5643 14 | 1554627538 6015 15 | 1554636529 5928 16 | 1554796073 6184 17 | 1554907976 6389 18 | 1554954569 6413 19 | 1554959259 7332 20 | 1554989912 7533 21 | 1554991064 7541 22 | 1555072123 7788 23 | 1555085433 7789 24 | 1555136856 7790 25 | 1555136888 7804 26 | 1555169004 7920 27 | 1555169499 7924 28 | 1555860320 8196 29 | 1555860583 8196 30 | 1555942644 8420 31 | -------------------------------------------------------------------------------- /code_statistics/lines_of_code.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'lines_of_code.png' 5 | unset key 6 | set yrange [0:] 7 | set xdata time 8 | set timefmt "%s" 9 | set format x "%Y-%m-%d" 10 | set grid y 11 | set ylabel "Lines" 12 | set xtics rotate 13 | set bmargin 6 14 | plot 'lines_of_code.dat' using 1:2 w lines 15 | -------------------------------------------------------------------------------- /code_statistics/lines_of_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/lines_of_code.png -------------------------------------------------------------------------------- /code_statistics/lines_of_code_by_author.dat: -------------------------------------------------------------------------------- 1 | 1552750651 672 2 | 1552750740 672 3 | 1552830542 1383 4 | 1552830782 1383 5 | 1552830816 1383 6 | 1552831114 1390 7 | 1552963622 1997 8 | 1553233085 2448 9 | 1553272015 3325 10 | 1553704535 3618 11 | 1553947684 3691 12 | 1554180111 3984 13 | 1554388037 7669 14 | 1554627538 8159 15 | 1554636529 8176 16 | 1554796073 8485 17 | 1554907976 8834 18 | 1554954569 8918 19 | 1554959259 9858 20 | 1554989912 10152 21 | 1554991064 10199 22 | 1555072123 10500 23 | 1555085433 10538 24 | 1555136856 10571 25 | 1555136888 10613 26 | 1555169004 10814 27 | 1555169499 10819 28 | 1555860320 11116 29 | 1555860583 11120 30 | 1555942644 11409 31 | -------------------------------------------------------------------------------- /code_statistics/lines_of_code_by_author.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set terminal png transparent size 640,480 5 | set output 'lines_of_code_by_author.png' 6 | set key left top 7 | set yrange [0:] 8 | set xdata time 9 | set timefmt "%s" 10 | set format x "%Y-%m-%d" 11 | set grid y 12 | set ylabel "Lines" 13 | set xtics rotate 14 | set bmargin 6 15 | plot 'lines_of_code_by_author.dat' using 1:2 title "吕西亚" w lines 16 | -------------------------------------------------------------------------------- /code_statistics/lines_of_code_by_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/lines_of_code_by_author.png -------------------------------------------------------------------------------- /code_statistics/month_of_year.dat: -------------------------------------------------------------------------------- 1 | 1 0 2 | 2 0 3 | 3 11 4 | 4 19 5 | 5 0 6 | 6 0 7 | 7 0 8 | 8 0 9 | 9 0 10 | 10 0 11 | 11 0 12 | 12 0 13 | -------------------------------------------------------------------------------- /code_statistics/month_of_year.plot: -------------------------------------------------------------------------------- 1 | set terminal png transparent size 640,240 2 | set size 1.0,1.0 3 | 4 | set output 'month_of_year.png' 5 | unset key 6 | set xrange [0.5:12.5] 7 | set yrange [0:] 8 | set xtics 1 9 | set grid y 10 | set ylabel "Commits" 11 | plot 'month_of_year.dat' using 1:2:(0.5) w boxes fs solid 12 | -------------------------------------------------------------------------------- /code_statistics/month_of_year.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/month_of_year.png -------------------------------------------------------------------------------- /code_statistics/sortable.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/code_statistics/sortable.js -------------------------------------------------------------------------------- /code_statistics/tags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GitStats - mynginx 6 | 7 | 8 | 9 | 10 | 11 |

Tags

12 | 22 |
Total tags
0
NameDateCommitsAuthors
-------------------------------------------------------------------------------- /config/log4cpp.properties: -------------------------------------------------------------------------------- 1 | # log4cpp.properties 2 | 3 | log4cpp.rootCategory=DEBUG, ACC 4 | log4cpp.category.err=DEBUG, ERR 5 | 6 | log4j.additivity.err=false 7 | 8 | log4cpp.appender.ACC=FileAppender 9 | log4cpp.appender.ACC.fileName=./Log/access.log 10 | # log4cpp.appender.ACC.maxFileSize=100*1024*1024 # 最大为100M 11 | log4cpp.appender.ACC.layout=PatternLayout 12 | log4cpp.appender.ACC.layout.ConversionPattern=%d [%p] %m%n 13 | 14 | log4cpp.appender.ERR=FileAppender 15 | log4cpp.appender.ERR.fileName=./Log/error.log 16 | log4cpp.appender.ERR.layout=PatternLayout 17 | log4cpp.appender.ERR.layout.ConversionPattern=%d [%p] %m%n -------------------------------------------------------------------------------- /config/lucia.conf: -------------------------------------------------------------------------------- 1 | # // 功能: 加载配置文件的单例类 2 | # // 描述: 配置文件解析说明 3 | # // 1. 以 "#" 开头的行作为注释 4 | # // 2. 以 "[" 开头的行作为注释 5 | # // 3. 以 "{" 开头的行作为注释 6 | # // 4. 以 "}" 开头的行作为注释 7 | # // 5. 每一行前后空格会被忽略 8 | # // 6. 空行会被忽略 9 | # // 7. 参数设置格式为: 设置名=参数 10 | # // 8. 参数行后面的 "#" 之后的作为注释 11 | # // 9. '\#' 代表 # 12 | # // 10. location 开头的表示一个静态资源映射地址 13 | # // 10.1 ~* 执行正则匹配,但不区分大小写 (四元组) location ~* pattern path 14 | # // 10.2 ~ 执行正则匹配,区分大小写 (四元组) location ~ pattern path 15 | # // 10.3 = 执行完全匹配 (四元组) location = pattern path 16 | # // 10.4 / 所有匹配 (三元组) location / path 17 | # // 10.5 ^~ 前缀匹配 (四元组)location ^~ pattern path 18 | # // 11. location 开头的表示一个RestFul API 19 | # // 11.1 ~* 执行正则匹配,但不区分大小写 (五元组) location ~* pattern API func 20 | # // 11.2 ~ 执行正则匹配,区分大小写 (五元组) location ~ pattern API func 21 | # // 11.3 = 执行完全匹配 (五元组) location = pattern API func 22 | # // 11.4 / 所有匹配 (四元组) location / API func 23 | # // 11.5 ^~ 前缀匹配 (五元组)location ^~ pattern API func 24 | # // 备注:为了更简洁方便地区分与静态资源服务器的区别,在func前需要加入关键字API,表示这是一个restful api请求 25 | 26 | 27 | 28 | [Log] # 读取日志的配置文件的相关信息 29 | log_properties = ../../config/log4cpp.properties # 日志配置文件地址,采用log4cpp的格式编写 30 | 31 | [Proc] # 进程相关信息 32 | workers = 4 # 创建 worker进程 的数量 33 | Daemon = 1 # 是否以守护进程运行,1表示守护进程,0表示非守护进程 34 | 35 | [Socket] # 网络编程的相关信息,会根据PortNumber 来判断监听几个端口,会根据Port+i 来选择端口 36 | PortNumber = 2 37 | Port1 = 8010 38 | Port2 = 8011 39 | 40 | Worker_connection = 256 # epoll 连接数量.这里影响着每个进程会创建多少个free_link节点,最多一次处理多少个kevent 41 | 42 | [ThreadPool] 43 | Thread_number = 10 # 线程池中的线程数量 44 | 45 | [Static resource mapping and Restful API mapping] # 静态资源映射, 地址的最后不要加 '/' 46 | { 47 | location = /404.html ./resource/static 48 | location ~* .(js|css|png|ico|jpg|jpeg|gif|html|json|eot|svg|ttf|woff|txt|gz|mp3|mp4)$ ./code_statistics 49 | 50 | location = /v1/test API TestController # restful api 请求 51 | 52 | #location ~* .(js|css|png|ico|jpg|jpeg|gif|html|json|eot|svg|ttf|woff|txt|gz|mp3|mp4)$ /Users/lxy/Desktop/mynginx/resource/static 53 | location / ./resource/static/others 54 | } 55 | 56 | # [Restful API mapping] 57 | # { 58 | # # @ /test TestController GET 59 | # } -------------------------------------------------------------------------------- /config/mime.types: -------------------------------------------------------------------------------- 1 | text/html html htm shtml 2 | text/css css 3 | text/xml xml 4 | image/gif gif 5 | image/jpeg jpeg jpg 6 | application/javascript js 7 | application/atom+xml atom 8 | application/rss+xml rss 9 | 10 | text/mathml mml 11 | text/plain txt 12 | text/vnd.sun.j2me.app-descriptor jad 13 | text/vnd.wap.wml wml 14 | text/x-component htc 15 | 16 | image/png png 17 | image/svg+xml svg svgz 18 | image/tiff tif tiff 19 | image/vnd.wap.wbmp wbmp 20 | image/webp webp 21 | image/x-icon ico 22 | image/x-jng jng 23 | image/x-ms-bmp bmp 24 | 25 | font/woff woff 26 | font/woff2 woff2 27 | 28 | application/java-archive jar war ear 29 | application/json json 30 | application/mac-binhex40 hqx 31 | application/msword doc 32 | application/pdf pdf 33 | application/postscript ps eps ai 34 | application/rtf rtf 35 | application/vnd.apple.mpegurl m3u8 36 | application/vnd.google-earth.kml+xml kml 37 | application/vnd.google-earth.kmz kmz 38 | application/vnd.ms-excel xls 39 | application/vnd.ms-fontobject eot 40 | application/vnd.ms-powerpoint ppt 41 | application/vnd.oasis.opendocument.graphics odg 42 | application/vnd.oasis.opendocument.presentation odp 43 | application/vnd.oasis.opendocument.spreadsheet ods 44 | application/vnd.oasis.opendocument.text odt 45 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx 46 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx 47 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx 48 | application/vnd.wap.wmlc wmlc 49 | application/x-7z-compressed 7z 50 | application/x-cocoa cco 51 | application/x-java-archive-diff jardiff 52 | application/x-java-jnlp-file jnlp 53 | application/x-makeself run 54 | application/x-perl pl pm 55 | application/x-pilot prc pdb 56 | application/x-rar-compressed rar 57 | application/x-redhat-package-manager rpm 58 | application/x-sea sea 59 | application/x-shockwave-flash swf 60 | application/x-stuffit sit 61 | application/x-tcl tcl tk 62 | application/x-x509-ca-cert der pem crt 63 | application/x-xpinstall xpi 64 | application/xhtml+xml xhtml 65 | application/xspf+xml xspf 66 | application/zip zip 67 | 68 | application/octet-stream bin exe dll 69 | application/octet-stream deb 70 | application/octet-stream dmg 71 | application/octet-stream iso img 72 | application/octet-stream msi msp msm 73 | 74 | audio/midi mid midi kar 75 | audio/mpeg mp3 76 | audio/ogg ogg 77 | audio/x-m4a m4a 78 | audio/x-realaudio ra 79 | 80 | video/3gpp 3gpp 3gp 81 | video/mp2t ts 82 | video/mp4 mp4 83 | video/mpeg mpeg mpg 84 | video/quicktime mov 85 | video/webm webm 86 | video/x-flv flv 87 | video/x-m4v m4v 88 | video/x-mng mng 89 | video/x-ms-asf asx asf 90 | video/x-ms-wmv wmv 91 | video/x-msvideo avi -------------------------------------------------------------------------------- /datapoll/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | # 指定生成目标 13 | #add_library(cia_datapoll SHARED ${DIR_SRCS}) 14 | add_library(cia_datapoll_static STATIC ${DIR_SRCS}) 15 | 16 | set_target_properties(cia_datapoll_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 17 | #set_target_properties(cia_datapoll PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | set_target_properties(cia_datapoll_static PROPERTIES OUTPUT_NAME "cia_datapoll") 19 | #set_target_properties(cia_datapoll PROPERTIES VERSION 1.0 SOVERSION 1) 20 | -------------------------------------------------------------------------------- /datapoll/cia_datapoll.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_datapoll.h" 2 | #include "cia_log.h" 3 | #include "cia_global.h" 4 | // 数据池 5 | 6 | DataPoll::DataPoll(){} 7 | DataPoll::~DataPoll(){} 8 | void DataPoll::inMsgQueue(Message* s){ 9 | { 10 | std::lock_guard sbguard(cia_mutex_message); 11 | requestQueue.push_back(s); 12 | } 13 | threadpoll.call_request(); 14 | // LOG_ACC(INFO, "收到数据包:%s", s); 15 | } 16 | Message* DataPoll::outMsgQueue(){ 17 | Message* buffer = NULL; 18 | { 19 | std::lock_guard sbguard(cia_mutex_message); 20 | if(requestQueue.empty()) return NULL; 21 | buffer = requestQueue.front(); 22 | requestQueue.pop_front(); 23 | } 24 | // LOG_ACC(INFO, "开始处理数据包:%s, 数据包的长度为:%d", buffer, strlen(buffer)); 25 | return buffer; 26 | } 27 | 28 | bool DataPoll::empty(){ 29 | std::lock_guard sbguard(cia_mutex_message); 30 | return requestQueue.empty(); 31 | } 32 | 33 | 34 | // 响应消息 35 | void DataPoll::inResQueue(Response* s){ 36 | { 37 | std::lock_guard sbguard(cia_mutex_response); 38 | responseQueue.push_back(s); 39 | } 40 | threadpoll.call_response(); 41 | } 42 | 43 | Response* DataPoll::outResQueue(){ 44 | Response* buffer = NULL; 45 | { 46 | std::lock_guard sbguard(cia_mutex_response); 47 | if(responseQueue.empty()) return NULL; 48 | buffer = responseQueue.front(); 49 | responseQueue.pop_front(); 50 | } 51 | return buffer; 52 | } 53 | bool DataPoll::resEmpty(){ 54 | std::lock_guard sbguard(cia_mutex_response); 55 | return responseQueue.empty(); 56 | } -------------------------------------------------------------------------------- /datapoll/cia_datapoll.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_DATA_POLL_H__ 2 | #define __HEADERS_CIA_DATA_POLL_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "cia_socket.h" 9 | // 数据池 10 | class DataPoll{ 11 | public: 12 | DataPoll(); 13 | ~DataPoll(); 14 | // 请求消息的队列 15 | void inMsgQueue(Message* s); 16 | Message* outMsgQueue(); 17 | bool empty(); 18 | 19 | // 响应消息的队列 20 | void inResQueue(Response* s); 21 | Response* outResQueue(); 22 | bool resEmpty(); 23 | 24 | private: 25 | // 请求消息的队列 26 | std::list requestQueue; 27 | std::mutex cia_mutex_message; // 用的互斥量 28 | 29 | // 响应消息的队列 30 | std::list responseQueue; 31 | std::mutex cia_mutex_response; 32 | }; 33 | 34 | #endif -------------------------------------------------------------------------------- /headers/cia_global.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_GLOBAL_H__ 2 | #define __HEADERS_CIA_GLOBAL_H__ 3 | 4 | #include "cia_socket.h" 5 | #include "cia_threadpoo.h" 6 | #include "cia_datapoll.h" 7 | 8 | //外部全局量声明 9 | extern int g_environment; // 环境变量的长度 10 | extern char **environ; // 环境变量。 11 | extern char **g_os_argv; // 命令行参数 12 | extern char *new_environment; // 新申请的环境变量区域,存这个值主要是程序删除时退出 13 | 14 | extern int process_type; // 是master进程还是worker进程,master进程为0, worker进程为1,2,3,4 15 | 16 | extern CSocket socket_ctl; 17 | extern CThreadPoll threadpoll; 18 | extern DataPoll datapoll; 19 | #endif 20 | -------------------------------------------------------------------------------- /headers/header.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_HEADER_H__ 2 | #define __HEADERS_HEADER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "log4cpp/Category.hh" 11 | #include "log4cpp/PropertyConfigurator.hh" 12 | 13 | #include 14 | #include 15 | #endif -------------------------------------------------------------------------------- /headers/http_parser.h.gch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/headers/http_parser.h.gch -------------------------------------------------------------------------------- /http-parser-master/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_parser) 13 | 14 | # 指定生成目标 15 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 16 | add_library("${CIA_OUTPUT_NAME}_static" STATIC ${DIR_SRCS}) 17 | 18 | set_target_properties("${CIA_OUTPUT_NAME}_static" PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 20 | set_target_properties("${CIA_OUTPUT_NAME}_static" PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 21 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 22 | -------------------------------------------------------------------------------- /http-parser-master/README.md: -------------------------------------------------------------------------------- 1 | HTTP Parser 2 | =========== 3 | 4 | [![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) 5 | 6 | This is a parser for HTTP messages written in C. It parses both requests and 7 | responses. The parser is designed to be used in performance HTTP 8 | applications. It does not make any syscalls nor allocations, it does not 9 | buffer data, it can be interrupted at anytime. Depending on your 10 | architecture, it only requires about 40 bytes of data per message 11 | stream (in a web server that is per connection). 12 | 13 | Features: 14 | 15 | * No dependencies 16 | * Handles persistent streams (keep-alive). 17 | * Decodes chunked encoding. 18 | * Upgrade support 19 | * Defends against buffer overflow attacks. 20 | 21 | The parser extracts the following information from HTTP messages: 22 | 23 | * Header fields and values 24 | * Content-Length 25 | * Request method 26 | * Response status code 27 | * Transfer-Encoding 28 | * HTTP version 29 | * Request URL 30 | * Message body 31 | 32 | 33 | Usage 34 | ----- 35 | 36 | One `http_parser` object is used per TCP connection. Initialize the struct 37 | using `http_parser_init()` and set the callbacks. That might look something 38 | like this for a request parser: 39 | ```c 40 | http_parser_settings settings; 41 | settings.on_url = my_url_callback; 42 | settings.on_header_field = my_header_field_callback; 43 | /* ... */ 44 | 45 | http_parser *parser = malloc(sizeof(http_parser)); 46 | http_parser_init(parser, HTTP_REQUEST); 47 | parser->data = my_socket; 48 | ``` 49 | 50 | When data is received on the socket execute the parser and check for errors. 51 | 52 | ```c 53 | size_t len = 80*1024, nparsed; 54 | char buf[len]; 55 | ssize_t recved; 56 | 57 | recved = recv(fd, buf, len, 0); 58 | 59 | if (recved < 0) { 60 | /* Handle error. */ 61 | } 62 | 63 | /* Start up / continue the parser. 64 | * Note we pass recved==0 to signal that EOF has been received. 65 | */ 66 | nparsed = http_parser_execute(parser, &settings, buf, recved); 67 | 68 | if (parser->upgrade) { 69 | /* handle new protocol */ 70 | } else if (nparsed != recved) { 71 | /* Handle error. Usually just close the connection. */ 72 | } 73 | ``` 74 | 75 | `http_parser` needs to know where the end of the stream is. For example, sometimes 76 | servers send responses without Content-Length and expect the client to 77 | consume input (for the body) until EOF. To tell `http_parser` about EOF, give 78 | `0` as the fourth parameter to `http_parser_execute()`. Callbacks and errors 79 | can still be encountered during an EOF, so one must still be prepared 80 | to receive them. 81 | 82 | Scalar valued message information such as `status_code`, `method`, and the 83 | HTTP version are stored in the parser structure. This data is only 84 | temporally stored in `http_parser` and gets reset on each new message. If 85 | this information is needed later, copy it out of the structure during the 86 | `headers_complete` callback. 87 | 88 | The parser decodes the transfer-encoding for both requests and responses 89 | transparently. That is, a chunked encoding is decoded before being sent to 90 | the on_body callback. 91 | 92 | 93 | The Special Problem of Upgrade 94 | ------------------------------ 95 | 96 | `http_parser` supports upgrading the connection to a different protocol. An 97 | increasingly common example of this is the WebSocket protocol which sends 98 | a request like 99 | 100 | GET /demo HTTP/1.1 101 | Upgrade: WebSocket 102 | Connection: Upgrade 103 | Host: example.com 104 | Origin: http://example.com 105 | WebSocket-Protocol: sample 106 | 107 | followed by non-HTTP data. 108 | 109 | (See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the 110 | WebSocket protocol.) 111 | 112 | To support this, the parser will treat this as a normal HTTP message without a 113 | body, issuing both on_headers_complete and on_message_complete callbacks. However 114 | http_parser_execute() will stop parsing at the end of the headers and return. 115 | 116 | The user is expected to check if `parser->upgrade` has been set to 1 after 117 | `http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied 118 | offset by the return value of `http_parser_execute()`. 119 | 120 | 121 | Callbacks 122 | --------- 123 | 124 | During the `http_parser_execute()` call, the callbacks set in 125 | `http_parser_settings` will be executed. The parser maintains state and 126 | never looks behind, so buffering the data is not necessary. If you need to 127 | save certain data for later usage, you can do that from the callbacks. 128 | 129 | There are two types of callbacks: 130 | 131 | * notification `typedef int (*http_cb) (http_parser*);` 132 | Callbacks: on_message_begin, on_headers_complete, on_message_complete. 133 | * data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` 134 | Callbacks: (requests only) on_url, 135 | (common) on_header_field, on_header_value, on_body; 136 | 137 | Callbacks must return 0 on success. Returning a non-zero value indicates 138 | error to the parser, making it exit immediately. 139 | 140 | For cases where it is necessary to pass local information to/from a callback, 141 | the `http_parser` object's `data` field can be used. 142 | An example of such a case is when using threads to handle a socket connection, 143 | parse a request, and then give a response over that socket. By instantiation 144 | of a thread-local struct containing relevant data (e.g. accepted socket, 145 | allocated memory for callbacks to write into, etc), a parser's callbacks are 146 | able to communicate data between the scope of the thread and the scope of the 147 | callback in a threadsafe manner. This allows `http_parser` to be used in 148 | multi-threaded contexts. 149 | 150 | Example: 151 | ```c 152 | typedef struct { 153 | socket_t sock; 154 | void* buffer; 155 | int buf_len; 156 | } custom_data_t; 157 | 158 | 159 | int my_url_callback(http_parser* parser, const char *at, size_t length) { 160 | /* access to thread local custom_data_t struct. 161 | Use this access save parsed data for later use into thread local 162 | buffer, or communicate over socket 163 | */ 164 | parser->data; 165 | ... 166 | return 0; 167 | } 168 | 169 | ... 170 | 171 | void http_parser_thread(socket_t sock) { 172 | int nparsed = 0; 173 | /* allocate memory for user data */ 174 | custom_data_t *my_data = malloc(sizeof(custom_data_t)); 175 | 176 | /* some information for use by callbacks. 177 | * achieves thread -> callback information flow */ 178 | my_data->sock = sock; 179 | 180 | /* instantiate a thread-local parser */ 181 | http_parser *parser = malloc(sizeof(http_parser)); 182 | http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ 183 | /* this custom data reference is accessible through the reference to the 184 | parser supplied to callback functions */ 185 | parser->data = my_data; 186 | 187 | http_parser_settings settings; /* set up callbacks */ 188 | settings.on_url = my_url_callback; 189 | 190 | /* execute parser */ 191 | nparsed = http_parser_execute(parser, &settings, buf, recved); 192 | 193 | ... 194 | /* parsed information copied from callback. 195 | can now perform action on data copied into thread-local memory from callbacks. 196 | achieves callback -> thread information flow */ 197 | my_data->buffer; 198 | ... 199 | } 200 | 201 | ``` 202 | 203 | In case you parse HTTP message in chunks (i.e. `read()` request line 204 | from socket, parse, read half headers, parse, etc) your data callbacks 205 | may be called more than once. `http_parser` guarantees that data pointer is only 206 | valid for the lifetime of callback. You can also `read()` into a heap allocated 207 | buffer to avoid copying memory around if this fits your application. 208 | 209 | Reading headers may be a tricky task if you read/parse headers partially. 210 | Basically, you need to remember whether last header callback was field or value 211 | and apply the following logic: 212 | 213 | (on_header_field and on_header_value shortened to on_h_*) 214 | ------------------------ ------------ -------------------------------------------- 215 | | State (prev. callback) | Callback | Description/action | 216 | ------------------------ ------------ -------------------------------------------- 217 | | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | 218 | | | | into it | 219 | ------------------------ ------------ -------------------------------------------- 220 | | value | on_h_field | New header started. | 221 | | | | Copy current name,value buffers to headers | 222 | | | | list and allocate new buffer for new name | 223 | ------------------------ ------------ -------------------------------------------- 224 | | field | on_h_field | Previous name continues. Reallocate name | 225 | | | | buffer and append callback data to it | 226 | ------------------------ ------------ -------------------------------------------- 227 | | field | on_h_value | Value for current header started. Allocate | 228 | | | | new buffer and copy callback data to it | 229 | ------------------------ ------------ -------------------------------------------- 230 | | value | on_h_value | Value continues. Reallocate value buffer | 231 | | | | and append callback data to it | 232 | ------------------------ ------------ -------------------------------------------- 233 | 234 | 235 | Parsing URLs 236 | ------------ 237 | 238 | A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. 239 | Users of this library may wish to use it to parse URLs constructed from 240 | consecutive `on_url` callbacks. 241 | 242 | See examples of reading in headers: 243 | 244 | * [partial example](http://gist.github.com/155877) in C 245 | * [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C 246 | * [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript 247 | -------------------------------------------------------------------------------- /http-parser-master/a.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/http-parser-master/a.out -------------------------------------------------------------------------------- /http-parser-master/cia_parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cia_parser.h" 3 | #include "cia_log.h" 4 | 5 | http_parser_settings CParser::settings; 6 | 7 | CParser::CParser(){ 8 | http_parser_init(&parser, HTTP_REQUEST); 9 | memset(&CParser::settings, 0, sizeof(CParser::settings)); 10 | CParser::settings.on_message_begin = on_message_begin; 11 | CParser::settings.on_url = on_url; 12 | CParser::settings.on_header_field = on_header_field; 13 | CParser::settings.on_header_value = on_header_value; 14 | CParser::settings.on_headers_complete = on_headers_complete; 15 | CParser::settings.on_body = on_body; 16 | CParser::settings.on_message_complete = on_message_complete; 17 | 18 | parser.data = &messagelist; 19 | // message.type = HTTP_REQUEST; 20 | } 21 | 22 | size_t CParser::parser_execute(const char *data, size_t len){ 23 | return http_parser_execute(&parser, &CParser::settings, data, len); 24 | } 25 | 26 | void CParser::restore(){ 27 | for(auto itre=messagelist.begin(); itre!=messagelist.end(); itre++){ 28 | if((*itre) != NULL){ 29 | delete (*itre); 30 | (*itre) = NULL; 31 | } 32 | } 33 | messagelist.clear(); 34 | http_parser_init(&parser, HTTP_REQUEST); 35 | } 36 | CParser::~CParser(){ 37 | http_parser_init(&parser, HTTP_REQUEST); 38 | } 39 | 40 | int CParser::on_message_begin(http_parser* _){ 41 | std::list *messgae = (std::list *)_->data; 42 | // LOG_ACC(INFO, "\n***MESSAGE BEGIN***\n\n"); 43 | Message* mess = new Message(); 44 | (*messgae).push_back(mess); 45 | (*messgae).back()->message_begin_cb_called = true; 46 | return 0; 47 | }; 48 | 49 | int CParser::on_headers_complete(http_parser* _){ 50 | std::list *messgae = (std::list *)_->data; 51 | // LOG_ACC("\n***HEADERS COMPLETE***\n\n"); 52 | (*messgae).back()->headers_complete_cb_called = true; 53 | return 0; 54 | }; 55 | int CParser::on_message_complete(http_parser* _){ 56 | std::list *messgae = (std::list *)_->data; 57 | (*messgae).back()->method = _->method; 58 | // LOG_ACC("\n***MESSAGE COMPLETE***\n\n"); 59 | (*messgae).back()->message_complete_cb_called = true; 60 | return 0; 61 | }; 62 | int CParser::on_url(http_parser* _, const char* at, size_t length){ 63 | std::list *messgae = (std::list *)_->data; 64 | // LOG_ACC("Url: %.*s\n", (int)length, at); 65 | (*messgae).back()->url = std::string(at, at+length); 66 | return 0; 67 | }; 68 | int CParser::on_header_field(http_parser* _, const char* at, size_t length){ 69 | std::list *messgae = (std::list *)_->data; 70 | // LOG_ACC("Header field: %.*s\n", (int)length, at); 71 | std::string header_field = std::string(at,at+length); 72 | (*messgae).back()->headers.push_back(std::vector{header_field}); 73 | (*messgae).back()->header_map[header_field] = (*messgae).back()->headers.size()-1; 74 | return 0; 75 | }; 76 | int CParser::on_header_value(http_parser* _, const char* at, size_t length){ 77 | std::list *messgae = (std::list *)_->data; 78 | // LOG_ACC("Header value: %.*s\n", (int)length, at); 79 | std::string header_v = std::string(at,at+length); 80 | (*messgae).back()->headers.back().push_back(header_v); 81 | return 0; 82 | }; 83 | int CParser::on_body(http_parser* _, const char* at, size_t length){ 84 | std::list *messgae = (std::list *)_->data; 85 | // LOG_ACC(INFO, "on_body接收到的数据大小是:%d", length); 86 | // LOG_ACC("Body: %.*s\n", (int)length, at); 87 | (*messgae).back()->body += std::string(at, at+length); 88 | return 0; 89 | }; 90 | 91 | 92 | -------------------------------------------------------------------------------- /http-parser-master/cia_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADER_CIA_PARSER_H__ 2 | #define __HEADER_CIA_PARSER_H__ 3 | #include "http_parser.h" 4 | #include "cia_comm.h" 5 | #include 6 | // 解析器:输入data流,输出message 7 | class CParser{ 8 | public: 9 | CParser(); 10 | ~CParser(); 11 | void restore(); 12 | size_t parser_execute(const char *data, size_t len); 13 | 14 | std::list messagelist; 15 | http_parser parser; 16 | 17 | static http_parser_settings settings; 18 | static int on_message_begin(http_parser* _); 19 | static int on_headers_complete(http_parser* _); 20 | static int on_message_complete(http_parser* _); 21 | static int on_url(http_parser* _, const char* at, size_t length); 22 | static int on_header_field(http_parser* _, const char* at, size_t length); 23 | static int on_header_value(http_parser* _, const char* at, size_t length); 24 | static int on_body(http_parser* _, const char* at, size_t length); 25 | }; 26 | #endif -------------------------------------------------------------------------------- /http-parser-master/http_parser.h: -------------------------------------------------------------------------------- 1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to 5 | * deal in the Software without restriction, including without limitation the 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | */ 21 | #ifndef http_parser_h 22 | #define http_parser_h 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /* Also update SONAME in the Makefile whenever you change these. */ 28 | #define HTTP_PARSER_VERSION_MAJOR 2 29 | #define HTTP_PARSER_VERSION_MINOR 9 30 | #define HTTP_PARSER_VERSION_PATCH 0 31 | 32 | #include 33 | #if defined(_WIN32) && !defined(__MINGW32__) && \ 34 | (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) 35 | #include 36 | typedef __int8 int8_t; 37 | typedef unsigned __int8 uint8_t; 38 | typedef __int16 int16_t; 39 | typedef unsigned __int16 uint16_t; 40 | typedef __int32 int32_t; 41 | typedef unsigned __int32 uint32_t; 42 | typedef __int64 int64_t; 43 | typedef unsigned __int64 uint64_t; 44 | #else 45 | #include 46 | #endif 47 | 48 | /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run 49 | * faster 50 | */ 51 | #ifndef HTTP_PARSER_STRICT 52 | # define HTTP_PARSER_STRICT 1 53 | #endif 54 | 55 | /* Maximium header size allowed. If the macro is not defined 56 | * before including this header then the default is used. To 57 | * change the maximum header size, define the macro in the build 58 | * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove 59 | * the effective limit on the size of the header, define the macro 60 | * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) 61 | */ 62 | #ifndef HTTP_MAX_HEADER_SIZE 63 | # define HTTP_MAX_HEADER_SIZE (80*1024) 64 | #endif 65 | 66 | typedef struct http_parser http_parser; 67 | typedef struct http_parser_settings http_parser_settings; 68 | 69 | 70 | /* Callbacks should return non-zero to indicate an error. The parser will 71 | * then halt execution. 72 | * 73 | * The one exception is on_headers_complete. In a HTTP_RESPONSE parser 74 | * returning '1' from on_headers_complete will tell the parser that it 75 | * should not expect a body. This is used when receiving a response to a 76 | * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: 77 | * chunked' headers that indicate the presence of a body. 78 | * 79 | * Returning `2` from on_headers_complete will tell parser that it should not 80 | * expect neither a body nor any futher responses on this connection. This is 81 | * useful for handling responses to a CONNECT request which may not contain 82 | * `Upgrade` or `Connection: upgrade` headers. 83 | * 84 | * http_data_cb does not return data chunks. It will be called arbitrarily 85 | * many times for each string. E.G. you might get 10 callbacks for "on_url" 86 | * each providing just a few characters more data. 87 | */ 88 | typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); 89 | typedef int (*http_cb) (http_parser*); 90 | 91 | 92 | /* Status Codes */ 93 | #define HTTP_STATUS_MAP(XX) \ 94 | XX(100, CONTINUE, Continue) \ 95 | XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ 96 | XX(102, PROCESSING, Processing) \ 97 | XX(200, OK, OK) \ 98 | XX(201, CREATED, Created) \ 99 | XX(202, ACCEPTED, Accepted) \ 100 | XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ 101 | XX(204, NO_CONTENT, No Content) \ 102 | XX(205, RESET_CONTENT, Reset Content) \ 103 | XX(206, PARTIAL_CONTENT, Partial Content) \ 104 | XX(207, MULTI_STATUS, Multi-Status) \ 105 | XX(208, ALREADY_REPORTED, Already Reported) \ 106 | XX(226, IM_USED, IM Used) \ 107 | XX(300, MULTIPLE_CHOICES, Multiple Choices) \ 108 | XX(301, MOVED_PERMANENTLY, Moved Permanently) \ 109 | XX(302, FOUND, Found) \ 110 | XX(303, SEE_OTHER, See Other) \ 111 | XX(304, NOT_MODIFIED, Not Modified) \ 112 | XX(305, USE_PROXY, Use Proxy) \ 113 | XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ 114 | XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ 115 | XX(400, BAD_REQUEST, Bad Request) \ 116 | XX(401, UNAUTHORIZED, Unauthorized) \ 117 | XX(402, PAYMENT_REQUIRED, Payment Required) \ 118 | XX(403, FORBIDDEN, Forbidden) \ 119 | XX(404, NOT_FOUND, Not Found) \ 120 | XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ 121 | XX(406, NOT_ACCEPTABLE, Not Acceptable) \ 122 | XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ 123 | XX(408, REQUEST_TIMEOUT, Request Timeout) \ 124 | XX(409, CONFLICT, Conflict) \ 125 | XX(410, GONE, Gone) \ 126 | XX(411, LENGTH_REQUIRED, Length Required) \ 127 | XX(412, PRECONDITION_FAILED, Precondition Failed) \ 128 | XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ 129 | XX(414, URI_TOO_LONG, URI Too Long) \ 130 | XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ 131 | XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ 132 | XX(417, EXPECTATION_FAILED, Expectation Failed) \ 133 | XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ 134 | XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ 135 | XX(423, LOCKED, Locked) \ 136 | XX(424, FAILED_DEPENDENCY, Failed Dependency) \ 137 | XX(426, UPGRADE_REQUIRED, Upgrade Required) \ 138 | XX(428, PRECONDITION_REQUIRED, Precondition Required) \ 139 | XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ 140 | XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ 141 | XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ 142 | XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ 143 | XX(501, NOT_IMPLEMENTED, Not Implemented) \ 144 | XX(502, BAD_GATEWAY, Bad Gateway) \ 145 | XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ 146 | XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ 147 | XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ 148 | XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ 149 | XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ 150 | XX(508, LOOP_DETECTED, Loop Detected) \ 151 | XX(510, NOT_EXTENDED, Not Extended) \ 152 | XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ 153 | 154 | enum http_status 155 | { 156 | #define XX(num, name, string) HTTP_STATUS_##name = num, 157 | HTTP_STATUS_MAP(XX) 158 | #undef XX 159 | }; 160 | 161 | 162 | /* Request Methods */ 163 | #define HTTP_METHOD_MAP(XX) \ 164 | XX(0, DELETE, DELETE) \ 165 | XX(1, GET, GET) \ 166 | XX(2, HEAD, HEAD) \ 167 | XX(3, POST, POST) \ 168 | XX(4, PUT, PUT) \ 169 | /* pathological */ \ 170 | XX(5, CONNECT, CONNECT) \ 171 | XX(6, OPTIONS, OPTIONS) \ 172 | XX(7, TRACE, TRACE) \ 173 | /* WebDAV */ \ 174 | XX(8, COPY, COPY) \ 175 | XX(9, LOCK, LOCK) \ 176 | XX(10, MKCOL, MKCOL) \ 177 | XX(11, MOVE, MOVE) \ 178 | XX(12, PROPFIND, PROPFIND) \ 179 | XX(13, PROPPATCH, PROPPATCH) \ 180 | XX(14, SEARCH, SEARCH) \ 181 | XX(15, UNLOCK, UNLOCK) \ 182 | XX(16, BIND, BIND) \ 183 | XX(17, REBIND, REBIND) \ 184 | XX(18, UNBIND, UNBIND) \ 185 | XX(19, ACL, ACL) \ 186 | /* subversion */ \ 187 | XX(20, REPORT, REPORT) \ 188 | XX(21, MKACTIVITY, MKACTIVITY) \ 189 | XX(22, CHECKOUT, CHECKOUT) \ 190 | XX(23, MERGE, MERGE) \ 191 | /* upnp */ \ 192 | XX(24, MSEARCH, M-SEARCH) \ 193 | XX(25, NOTIFY, NOTIFY) \ 194 | XX(26, SUBSCRIBE, SUBSCRIBE) \ 195 | XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ 196 | /* RFC-5789 */ \ 197 | XX(28, PATCH, PATCH) \ 198 | XX(29, PURGE, PURGE) \ 199 | /* CalDAV */ \ 200 | XX(30, MKCALENDAR, MKCALENDAR) \ 201 | /* RFC-2068, section 19.6.1.2 */ \ 202 | XX(31, LINK, LINK) \ 203 | XX(32, UNLINK, UNLINK) \ 204 | /* icecast */ \ 205 | XX(33, SOURCE, SOURCE) \ 206 | 207 | enum http_method 208 | { 209 | #define XX(num, name, string) HTTP_##name = num, 210 | HTTP_METHOD_MAP(XX) 211 | #undef XX 212 | }; 213 | 214 | 215 | enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; 216 | 217 | 218 | /* Flag values for http_parser.flags field */ 219 | enum flags 220 | { F_CHUNKED = 1 << 0 221 | , F_CONNECTION_KEEP_ALIVE = 1 << 1 222 | , F_CONNECTION_CLOSE = 1 << 2 223 | , F_CONNECTION_UPGRADE = 1 << 3 224 | , F_TRAILING = 1 << 4 225 | , F_UPGRADE = 1 << 5 226 | , F_SKIPBODY = 1 << 6 227 | , F_CONTENTLENGTH = 1 << 7 228 | }; 229 | 230 | 231 | /* Map for errno-related constants 232 | * 233 | * The provided argument should be a macro that takes 2 arguments. 234 | */ 235 | #define HTTP_ERRNO_MAP(XX) \ 236 | /* No error */ \ 237 | XX(OK, "success") \ 238 | \ 239 | /* Callback-related errors */ \ 240 | XX(CB_message_begin, "the on_message_begin callback failed") \ 241 | XX(CB_url, "the on_url callback failed") \ 242 | XX(CB_header_field, "the on_header_field callback failed") \ 243 | XX(CB_header_value, "the on_header_value callback failed") \ 244 | XX(CB_headers_complete, "the on_headers_complete callback failed") \ 245 | XX(CB_body, "the on_body callback failed") \ 246 | XX(CB_message_complete, "the on_message_complete callback failed") \ 247 | XX(CB_status, "the on_status callback failed") \ 248 | XX(CB_chunk_header, "the on_chunk_header callback failed") \ 249 | XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ 250 | \ 251 | /* Parsing-related errors */ \ 252 | XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ 253 | XX(HEADER_OVERFLOW, \ 254 | "too many header bytes seen; overflow detected") \ 255 | XX(CLOSED_CONNECTION, \ 256 | "data received after completed connection: close message") \ 257 | XX(INVALID_VERSION, "invalid HTTP version") \ 258 | XX(INVALID_STATUS, "invalid HTTP status code") \ 259 | XX(INVALID_METHOD, "invalid HTTP method") \ 260 | XX(INVALID_URL, "invalid URL") \ 261 | XX(INVALID_HOST, "invalid host") \ 262 | XX(INVALID_PORT, "invalid port") \ 263 | XX(INVALID_PATH, "invalid path") \ 264 | XX(INVALID_QUERY_STRING, "invalid query string") \ 265 | XX(INVALID_FRAGMENT, "invalid fragment") \ 266 | XX(LF_EXPECTED, "LF character expected") \ 267 | XX(INVALID_HEADER_TOKEN, "invalid character in header") \ 268 | XX(INVALID_CONTENT_LENGTH, \ 269 | "invalid character in content-length header") \ 270 | XX(UNEXPECTED_CONTENT_LENGTH, \ 271 | "unexpected content-length header") \ 272 | XX(INVALID_CHUNK_SIZE, \ 273 | "invalid character in chunk size header") \ 274 | XX(INVALID_CONSTANT, "invalid constant string") \ 275 | XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ 276 | XX(STRICT, "strict mode assertion failed") \ 277 | XX(PAUSED, "parser is paused") \ 278 | XX(UNKNOWN, "an unknown error occurred") 279 | 280 | 281 | /* Define HPE_* values for each errno value above */ 282 | #define HTTP_ERRNO_GEN(n, s) HPE_##n, 283 | enum http_errno { 284 | HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) 285 | }; 286 | #undef HTTP_ERRNO_GEN 287 | 288 | 289 | /* Get an http_errno value from an http_parser */ 290 | #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) 291 | 292 | 293 | struct http_parser { 294 | /** PRIVATE **/ 295 | unsigned int type : 2; /* enum http_parser_type */ 296 | unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ 297 | unsigned int state : 7; /* enum state from http_parser.c */ 298 | unsigned int header_state : 7; /* enum header_state from http_parser.c */ 299 | unsigned int index : 7; /* index into current matcher */ 300 | unsigned int lenient_http_headers : 1; 301 | 302 | uint32_t nread; /* # bytes read in various scenarios */ 303 | uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ 304 | 305 | /** READ-ONLY **/ 306 | unsigned short http_major; 307 | unsigned short http_minor; 308 | unsigned int status_code : 16; /* responses only */ 309 | unsigned int method : 8; /* requests only */ 310 | unsigned int http_errno : 7; 311 | 312 | /* 1 = Upgrade header was present and the parser has exited because of that. 313 | * 0 = No upgrade header present. 314 | * Should be checked when http_parser_execute() returns in addition to 315 | * error checking. 316 | */ 317 | unsigned int upgrade : 1; 318 | 319 | /** PUBLIC **/ 320 | void *data; /* A pointer to get hook to the "connection" or "socket" object */ 321 | }; 322 | 323 | 324 | struct http_parser_settings { 325 | http_cb on_message_begin; 326 | http_data_cb on_url; 327 | http_data_cb on_status; 328 | http_data_cb on_header_field; 329 | http_data_cb on_header_value; 330 | http_cb on_headers_complete; 331 | http_data_cb on_body; 332 | http_cb on_message_complete; 333 | /* When on_chunk_header is called, the current chunk length is stored 334 | * in parser->content_length. 335 | */ 336 | http_cb on_chunk_header; 337 | http_cb on_chunk_complete; 338 | }; 339 | 340 | 341 | enum http_parser_url_fields 342 | { UF_SCHEMA = 0 343 | , UF_HOST = 1 344 | , UF_PORT = 2 345 | , UF_PATH = 3 346 | , UF_QUERY = 4 347 | , UF_FRAGMENT = 5 348 | , UF_USERINFO = 6 349 | , UF_MAX = 7 350 | }; 351 | 352 | 353 | /* Result structure for http_parser_parse_url(). 354 | * 355 | * Callers should index into field_data[] with UF_* values iff field_set 356 | * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and 357 | * because we probably have padding left over), we convert any port to 358 | * a uint16_t. 359 | */ 360 | struct http_parser_url { 361 | uint16_t field_set; /* Bitmask of (1 << UF_*) values */ 362 | uint16_t port; /* Converted UF_PORT string */ 363 | 364 | struct { 365 | uint16_t off; /* Offset into buffer in which field starts */ 366 | uint16_t len; /* Length of run in buffer */ 367 | } field_data[UF_MAX]; 368 | }; 369 | 370 | 371 | /* Returns the library version. Bits 16-23 contain the major version number, 372 | * bits 8-15 the minor version number and bits 0-7 the patch level. 373 | * Usage example: 374 | * 375 | * unsigned long version = http_parser_version(); 376 | * unsigned major = (version >> 16) & 255; 377 | * unsigned minor = (version >> 8) & 255; 378 | * unsigned patch = version & 255; 379 | * printf("http_parser v%u.%u.%u\n", major, minor, patch); 380 | */ 381 | unsigned long http_parser_version(void); 382 | 383 | void http_parser_init(http_parser *parser, enum http_parser_type type); 384 | 385 | 386 | /* Initialize http_parser_settings members to 0 387 | */ 388 | void http_parser_settings_init(http_parser_settings *settings); 389 | 390 | 391 | /* Executes the parser. Returns number of parsed bytes. Sets 392 | * `parser->http_errno` on error. */ 393 | size_t http_parser_execute(http_parser *parser, 394 | const http_parser_settings *settings, 395 | const char *data, 396 | size_t len); 397 | 398 | 399 | /* If http_should_keep_alive() in the on_headers_complete or 400 | * on_message_complete callback returns 0, then this should be 401 | * the last message on the connection. 402 | * If you are the server, respond with the "Connection: close" header. 403 | * If you are the client, close the connection. 404 | */ 405 | int http_should_keep_alive(const http_parser *parser); 406 | 407 | /* Returns a string version of the HTTP method. */ 408 | const char *http_method_str(enum http_method m); 409 | 410 | /* Returns a string version of the HTTP status code. */ 411 | const char *http_status_str(enum http_status s); 412 | 413 | /* Return a string name of the given error */ 414 | const char *http_errno_name(enum http_errno err); 415 | 416 | /* Return a string description of the given error */ 417 | const char *http_errno_description(enum http_errno err); 418 | 419 | /* Initialize all http_parser_url members to 0 */ 420 | void http_parser_url_init(struct http_parser_url *u); 421 | 422 | /* Parse a URL; return nonzero on failure */ 423 | int http_parser_parse_url(const char *buf, size_t buflen, 424 | int is_connect, 425 | struct http_parser_url *u); 426 | 427 | /* Pause or un-pause the parser; a nonzero value pauses */ 428 | void http_parser_pause(http_parser *parser, int paused); 429 | 430 | /* Checks if this is the final chunk of the body. */ 431 | int http_body_is_final(const http_parser *parser); 432 | 433 | /* Change the maximum header size provided at compile time. */ 434 | void http_parser_set_max_header_size(uint32_t size); 435 | 436 | #ifdef __cplusplus 437 | } 438 | #endif 439 | #endif 440 | -------------------------------------------------------------------------------- /logs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_log) 13 | # 指定生成目标 14 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library("${CIA_OUTPUT_NAME}_static" STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties("${CIA_OUTPUT_NAME}_static" PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties("${CIA_OUTPUT_NAME}_static" PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /logs/cia_kernal_func.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "cia_kernal_func.h" 3 | 4 | void cia_logs_init(){ 5 | CClog& clog = CClog::getLog(); 6 | } 7 | -------------------------------------------------------------------------------- /logs/cia_kernal_func.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_KERNAL_CIA_FUNC_H__ 2 | #define __HEADERS_KERNAL_CIA_FUNC_H__ 3 | #include "cia_log.h" 4 | 5 | // ---------- 日志文件初始化 ------------------- 6 | void cia_logs_init(); 7 | // ---------- 信号初始化 ---------------------- 8 | int cia_init_signals(); 9 | // ---------- 开始执行创建子进程 --------------- 10 | void cia_master_process_cycle(); 11 | // ---------- 设置守护进程 -------------------- 12 | int cia_daemon(); 13 | 14 | void cia_process_events_and_timers(); // worker的业务处理程序 15 | #endif 16 | -------------------------------------------------------------------------------- /logs/cia_log.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_log.h" 2 | 3 | CClog::CClog(){ 4 | init(); 5 | } 6 | 7 | CClog::~CClog(){ 8 | cleanup(); 9 | } 10 | 11 | void CClog::init(){ 12 | // 1 读取解析配置文件, 默认为 "log4cpp.properties" 13 | // 读取出错, 完全可以忽略,可以定义一个缺省策略或者使用系统缺省策略 14 | // BasicLayout输出所有优先级日志到ConsoleAppender 15 | try{ 16 | 17 | std::string configname = CConfig::getInstance()->GetString("log_properties"); 18 | if(configname.length() <= 0){ 19 | configname = "./config/log4cpp.properties"; 20 | } 21 | 22 | log4cpp::PropertyConfigurator::configure(configname); // 加载配置文件 23 | 24 | log4cpp::Category& rot = log4cpp::Category::getRoot(); 25 | access = &rot; // 访问日志文件 26 | log4cpp::Category& eor = log4cpp::Category::getInstance(std::string("err")); 27 | error = &eor; // 错误日志文件 28 | 29 | }catch(std::exception e){ 30 | std::cout << "加载配置文件出现错误,程序强制退出" << std::endl; 31 | exit(-1); // 直接退出 32 | } 33 | } 34 | void CClog::cleanup(){ 35 | log4cpp::Category::shutdown(); 36 | } 37 | 38 | CClog& CClog::getLog(){ 39 | static CClog cclog; 40 | return cclog; 41 | } 42 | 43 | void CClog::access_log(int priority, const char* info, ...){ 44 | va_list args; 45 | va_start(args, info); 46 | // TODO 解析参数 47 | std::string result; 48 | 49 | if(args_printf(result, info, args) < 0){ 50 | va_end(args); 51 | return ; 52 | } 53 | va_end(args); 54 | access->log(priority, result); 55 | } 56 | void CClog::error_log(int priority, const char* info, ...){ 57 | va_list args; 58 | va_start(args, info); 59 | // TODO 解析参数 60 | std::string result; 61 | 62 | if(args_printf(result, info, args) < 0){ 63 | va_end(args); 64 | return ; 65 | } 66 | va_end(args); 67 | 68 | error->log(priority, result); 69 | } 70 | 71 | -------------------------------------------------------------------------------- /logs/cia_log.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __HEADERS_CIA_LOG_H__ 3 | #define __HEADERS_CIA_LOG_H__ 4 | #include "header.h" 5 | #include "cia_func.h" 6 | #include "cia_conf.h" 7 | /** 8 | * 使用 log4cpp 作为日志打印库 9 | * log4cpp有3个主要的组件:categories(类别)、appenders(附加目的地)、和 layouts(布局)。 10 | * a) layout类控制输出日志消息的显示样式: log4cpp::BasicLayout log4cpp::PatternLayout log4cpp::SimpleLayout 11 | * b) appender类用来输出日志(被layout格式化后的)到一些设备上。比如文件、syslog服务、某个socket等。 12 | * appender和layout的关系是layout附在appender上(通过appender.setlayout),appender类调用layout处理完日志消息后,记录到某个设备上。 13 | * log4cpp当前提供以下appender: 14 | * log4cpp::IdsaAppender // // 发送到IDS或者logger, 详细见 http://jade.cs.uct.ac.za/idsa/ 15 | * log4cpp::FileAppender // 输出到文件 16 | * log4cpp::RollingFileAppender // 输出到回卷文件,即当文件到达某个大小后回卷 17 | * 18 | * log4cpp::OstreamAppender // 输出到一个ostream类 19 | * log4cpp::RemoteSyslogAppender // 输出到远程syslog服务器 20 | * log4cpp::StringQueueAppender // 内存队列 21 | * log4cpp::SyslogAppender // 本地syslog 22 | * log4cpp::Win32DebugAppender // 发送到缺省系统调试器 23 | * log4cpp::NTEventLogAppender // 发送到win 事件日志 24 | * c) categories类真正完成记录日志功能,两个主要组成部分是appenders和priority(优先级) 25 | * 优先级:NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG 26 | * 27 | * 28 | **/ 29 | 30 | // 定义两个宏函数, LOG_ACC 为访问日志, LOG_ERR为启动错误日志 31 | // 参数level为log4cpp::Priority::Value 的 值, 取值为NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG 32 | #define LOG_ACC(level, format, args...) do {\ 33 | CClog::getLog().access_log(level, format, ##args);\ 34 | }while(0); 35 | 36 | 37 | #define LOG_ERR(level, format, args...) do {\ 38 | CClog::getLog().error_log(level, format, ##args); \ 39 | }while(0); 40 | 41 | // 定义错误级别 42 | 43 | #define DEBUG log4cpp::Priority::DEBUG 44 | #define INFO log4cpp::Priority::INFO 45 | #define NOTICE log4cpp::Priority::NOTICE 46 | #define WARN log4cpp::Priority::WARN 47 | #define ERROR log4cpp::Priority::ERROR 48 | #define CRIT log4cpp::Priority::CRIT 49 | #define ALERT log4cpp::Priority::ALERT 50 | #define FATAL log4cpp::Priority::FATAL 51 | 52 | class CClog{ 53 | private: 54 | CClog(); 55 | // CClog(const std::string& configname); 56 | 57 | void init(); 58 | 59 | public: 60 | void cleanup(); 61 | ~CClog(); 62 | 63 | static CClog& getLog(); 64 | 65 | void access_log(int priority, const char* info, ...); 66 | void error_log(int priority, const char* info, ...); 67 | 68 | private: 69 | log4cpp::Category* access; // 该文件表示业务的日志文件 70 | log4cpp::Category* error; // 该文件表示系统的加载运行文件 71 | }; 72 | 73 | #endif -------------------------------------------------------------------------------- /lucia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/lucia -------------------------------------------------------------------------------- /lucia.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.lucia 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleVersion 18 | 1 19 | 20 | 21 | -------------------------------------------------------------------------------- /lucia.dSYM/Contents/Resources/DWARF/lucia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/lucia.dSYM/Contents/Resources/DWARF/lucia -------------------------------------------------------------------------------- /net/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_net) 13 | # 指定生成目标 14 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library(${CIA_OUTPUT_NAME}_static STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /net/cia_comm.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_COMM_H__ 2 | #define __HEADERS_CIA_COMM_H__ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "http_parser.h" 12 | 13 | #define PKG_UNUSE -1 // 当前节点还在空闲连接池里面呐 14 | #define PKG_INIT 0 // 当前节点从连接池中拿了出来,但是还没有接受数据 15 | #define PKG_BD_RECVING 1 // 已经接受了部分数据,但是还没有完成数据 16 | #define PKG_BD_FINISH 2 // 数据接收完毕 17 | 18 | 19 | #define MAX_ELEMENT_SIZE 2048 20 | #define MAX_HEADERS 13 21 | 22 | // request; 23 | class Message { // 目前message只是处理了request的数据,reponse的数据需要额外处理,需要的时候另说 24 | public: 25 | Message():message_begin_cb_called(false),headers_complete_cb_called(false),message_complete_cb_called(false){} 26 | 27 | void clear(){ 28 | message_begin_cb_called = false; 29 | headers_complete_cb_called = false; 30 | message_complete_cb_called = false; 31 | fd = 0; 32 | url.clear(); 33 | body.clear(); 34 | headers.clear(); 35 | headers.shrink_to_fit(); 36 | header_map.clear(); 37 | 38 | post_body.clear(); 39 | } 40 | enum http_parser_type type; // HTTP_REQUEST HTTP_REPONSE 41 | int method; // 1-GET 3-POST 42 | 43 | int fd; // 那个文件描述符的消息 44 | 45 | // 存储 request 的报文头部信息 46 | std::string url; 47 | std::string body; 48 | std::vector> headers; 49 | std::map header_map; // 头文件的header与所在headers的映射 last_modified: 1 means headers[1] = "XXXX GMT"(last_modified) 50 | 51 | bool message_begin_cb_called; 52 | bool headers_complete_cb_called; 53 | bool message_complete_cb_called; 54 | 55 | // 存储 post 信息的相关内容 56 | std::unordered_map post_body; // 用来存储 post 信息的相关数据。 post数据中一般有 name : value 57 | 58 | 59 | }; 60 | 61 | // class FileStream{ 62 | // public: 63 | // FileStream():filedesc(0), send_begin(0), file_left_size(-1){} 64 | // int filedesc; 65 | // int send_begin; 66 | // int file_left_size; 67 | // }; 68 | 69 | class Response{ 70 | public: 71 | ~Response(){ 72 | if(msg != NULL) delete []msg; 73 | clear(); 74 | } 75 | Response():msg(NULL), begin(NULL), left_len(-1), send_count(0), msg_finished(false){ 76 | } 77 | Response(char* s, size_t length):msg(s), begin(s), left_len(length), send_count(0), msg_finished(false){ 78 | } 79 | void clear(){ 80 | send_count = 0; 81 | msg = NULL; 82 | begin = NULL; 83 | left_len = -1; 84 | fd = 0; 85 | msg_finished = false; 86 | file_list.clear(); 87 | } 88 | char* msg; // 指向response,可能需要构造一下response的结构,之后再议 89 | char* begin; 90 | 91 | size_t left_len; // header头文件相关的信息 92 | 93 | bool msg_finished; // msg区域是否发送完成 94 | std::list file_list; // 需要加锁的,避免多个线程同时往这个response中加数据 95 | 96 | std::atomic send_count; 97 | int fd; // 发送到文件描述符fd处去 98 | }; 99 | 100 | #endif -------------------------------------------------------------------------------- /net/cia_response_header.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_RESPONSE_HEADER_H__ 2 | #define __HEADERS_CIA_RESPONSE_HEADER_H__ 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "cia_func.h" 9 | // HTTP/1.1 200 OK 10 | // Server: nginx 11 | // Date: Mon, 08 Apr 2019 12:02:37 GMT 12 | // Content-Type: text/html; charset=utf-8 13 | // Content-Length: 848 14 | // Last-Modified: Thu, 06 Dec 2018 06:47:45 GMT 15 | // Connection: keep-alive 16 | // ETag: "5c08c611-350" 17 | // Accept-Ranges: bytes 18 | 19 | //https://zh.wikipedia.org/wiki/HTTP%E5%A4%B4%E5%AD%97%E6%AE%B5 关于响应报文的wiki 20 | // 先这样写,之后再修正增加; 21 | class Cia_Response_Header{ 22 | public: 23 | 24 | std::string getHeader(){ // 可以优化避免copy 25 | std::string result; 26 | time_t rawTime; 27 | time(&rawTime); 28 | 29 | result = "HTTP/1.1 " + code + " " + code_ds + "\r\n"; 30 | result += ("Server: Lucia/0.0.1 (Unix)\r\n"); 31 | result += ("Date: " + GetGmtTime(&rawTime) + "\r\n"); 32 | result += ("Content-Type: " + Content_Type + "\r\n"); 33 | if(Last_Modified.length() > 0) result += ("Last-Modified: " + Last_Modified + "\r\n"); 34 | if(Connection.length() > 0) result += ("Connection: " + Connection + "\r\n"); 35 | if(Content_Length.length() > 0) result += ("content-length: " + Content_Length + "\r\n"); 36 | result += ("Accept-Ranges: none\r\n"); 37 | result += "\r\n"; 38 | return result; 39 | } 40 | 41 | // std::string HTTP_Version; //==HTTP/1.1 42 | std::string code; 43 | std::string code_ds; 44 | std::string Content_Type; 45 | std::string Content_Length; 46 | std::string Last_Modified; 47 | std::string Connection; 48 | // std::string ETag; 49 | // std::string Accept_Ranges; // == none, 表示不支持范围获取 50 | 51 | }; 52 | #endif -------------------------------------------------------------------------------- /net/cia_socket.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_socket.h" 2 | #include "cia_kernal_func.h" 3 | 4 | CSocket::CSocket():free_link(NULL),kqueue_fd(-1){} 5 | CSocket::~CSocket(){ 6 | closesocket(); 7 | if(free_link != NULL) delete free_link; 8 | if(kqueue_fd > 3) close(kqueue_fd); 9 | } 10 | 11 | // 返回值表示是否创建成功一个,如果一个都没创建成功,直接退出程序 12 | bool CSocket::socket_init(){ 13 | // socket() 14 | // setsocketopt()设置为非阻塞,且为了避免Time_wait导致的端口已被占用的情况,使用SO_REUSEADDR 15 | // 循环bind()指定的端口 16 | // 然后listen()端口,但是注意的是listen的监听的文件描述符是要放到epoll中去的,每次epoll_wait获得连接时,通过对应的动作(accept())来处理 17 | int sock; 18 | bool init_success = false; 19 | 20 | CConfig *conf = CConfig::getInstance(); 21 | int ports = conf->GetIntDefault("PortNumber"); // port的数量 22 | 23 | struct sockaddr_in serv_addr; 24 | serv_addr.sin_family = AF_INET; // 表示ipv4 25 | serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 表示服务器上任意网卡的ip地址 26 | 27 | for(int i=0; iGetIntDefault("Port"+std::to_string(i+1)); // 端口 29 | 30 | if(port1 < 0){ // 表示没有这个,所以要加个Warning 31 | LOG_ERR(WARN, "配置文件中的端口 Port%d 出现错误, 已经跳过该端口的监听。", (i+1)); 32 | continue; 33 | } 34 | sock = socket(AF_INET, SOCK_STREAM, 0); // TCP ipv4固定组合 35 | if(sock == -1){ // 程序直接退出 36 | LOG_ERR(ERROR, "CSocket::socket_init() 中 socket() 创建失败,直接退出!"); 37 | return false; 38 | } 39 | int optval = 1; // 表示使用设定,为0表示不使用设定 40 | if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &optval, sizeof(optval)) == -1){ 41 | close(sock); 42 | LOG_ERR(ERROR, "CSocket::socket_init() 中 setsockopt() 设置失败,直接退出!"); 43 | return false; 44 | } 45 | if(!setnoneblocking(sock)){ 46 | close(sock); 47 | LOG_ERR(ERROR, "CSocket::socket_init() 中 setnoneblocking() 设置非阻塞失败,直接退出!"); 48 | return false; 49 | } 50 | 51 | serv_addr.sin_port = htons(port1); // htons = uint16_t, htonl = uint32_t 52 | if(bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1){ 53 | close(sock); 54 | LOG_ERR(ERROR, "CSocket::socket_init() 中 bind() 绑定端口失败,直接退出!"); 55 | return false; 56 | } 57 | int backlog = 1024; 58 | if(listen(sock, backlog) == -1){ 59 | close(sock); 60 | LOG_ERR(ERROR, "CSocket::socket_init() 中 listen() 监听端口失败,直接退出!"); 61 | return false; 62 | } 63 | FD_PORT* fd_port = new FD_PORT(sock,true, port1); 64 | fd_ports.push_back(fd_port); 65 | 66 | init_success = true; 67 | LOG_ERR(INFO, "端口 %d 监听成功!", port1); 68 | 69 | } 70 | if(init_success){ 71 | return true; 72 | } 73 | return false; 74 | // socket() 75 | 76 | } 77 | 78 | bool CSocket::setnoneblocking(int fd){ 79 | int flags; 80 | if(( flags = fcntl(fd, F_GETFL, 0)) < 0){ 81 | return false; 82 | } 83 | flags |= O_NONBLOCK; 84 | if(fcntl(fd, F_SETFL, flags) < 0){ 85 | return false; 86 | } 87 | return true; 88 | } 89 | 90 | void CSocket::closesocket(){ 91 | 92 | for(int i=0; ifd); 94 | if(fd_ports[i]->event != NULL){ 95 | // fd_ports[i]->event->clear(); // 所有和event先关的删除操作要先通过一部clear。 96 | // delete fd_ports[i]->event; 97 | free_link->insert_Node(fd_ports[i]->event); 98 | fd_ports[i]->event = NULL; 99 | } 100 | 101 | delete fd_ports[i]; 102 | fd_ports[i] = NULL; 103 | } 104 | } 105 | 106 | bool CSocket::epoll_init(){ //epoll的使用是linux only 而 macos是unix-like的,所以使用的是kqueue; 107 | #ifdef __linux__ // linux操作系统 epoll 108 | return epoll_init_linux(); 109 | #elif __APPLE__ // macos操作系统 kqueue 110 | return epoll_init_macos(); 111 | #else 112 | return fasle; 113 | #endif 114 | } 115 | 116 | bool CSocket::cia_add_epoll(FD_PORT* fd_port, int read, int write, cia_event_handler_ptr handler, Response* response, uint32_t event_type){ 117 | #ifdef __linux__ // linux操作系统 epoll 118 | return cia_operate_epoll_linux(fd_port, read, write, handler, response, event_type); 119 | #elif __APPLE__ // macos操作系统 kqueue 120 | return cia_add_epoll_macos(fd_port, read, write, handler, response); 121 | #else 122 | return false; 123 | #endif 124 | } 125 | void CSocket::cia_del_epoll(int fd, bool wr_flag){ 126 | #ifdef __linux__ // linux操作系统 epoll 127 | return cia_del_epoll_linux(fd, wr_flag); 128 | #elif __APPLE__ // macos操作系统 kqueue 129 | return cia_del_epoll_macos(fd, wr_flag); 130 | #else 131 | return fasle; 132 | #endif 133 | } 134 | 135 | 136 | // 添加一个文件描述符到kqueue中去,向fd_ports中加入一个,该函数并没有加,所以要在外面加,然后申请一个free_node 137 | // 参考accept,一定要在fd_ports中加入一条 138 | // read 表示读描述符,write表示写描述符,handler为回调函数 139 | #ifdef __linux__ 140 | 141 | 142 | bool CSocket::epoll_init_linux(){ 143 | 144 | work_connection = CConfig::getInstance()->GetIntDefault("Worker_connection"); 145 | 146 | kqueue_fd = epoll_create(work_connection); 147 | 148 | if(kqueue_fd == -1){ 149 | LOG_ERR(ERROR, "worker进程pid=%d中CSocket::epoll_init() 中 kqueue() 监听端口失败,直接退出!",getpid()) ; 150 | return false; 151 | } 152 | free_link = new FreeLink(work_connection); 153 | 154 | // struct kevent event_list[node_number]; // kevent返回的数据结构 155 | int er_judge = -1; 156 | for(int i=0; iwr_flag?1:0, fd_port->wr_flag?0:1, &CSocket::cia_socket_accept) == false){ 159 | er_judge = i; 160 | break; 161 | } 162 | } 163 | if(er_judge >= 0){ 164 | // 在这里面把内存释放了 165 | for(int i=0; ievent != NULL){ 168 | // fd_port->event->clear(); // 所有和event先关的删除操作要先通过一部clear。 169 | free_link->insert_Node(fd_port->event); 170 | // delete fd_port->event; 171 | fd_port->event = NULL; 172 | } 173 | } 174 | close(kqueue_fd); 175 | 176 | return false; 177 | } 178 | 179 | return true; 180 | 181 | } 182 | 183 | bool CSocket::cia_operate_epoll_linux(FD_PORT* fd_port_ori, int read, int write, cia_event_handler_ptr handler, Response* response, uint32_t event_type){ 184 | 185 | uint32_t truth_type = event_type; 186 | 187 | 188 | struct epoll_event ev; 189 | 190 | //int op; 191 | memset(&ev, 0, sizeof(ev)); 192 | 193 | FD_PORT* fd_port = fd_port_ori; 194 | Kevent_Node* kevent_node = NULL; 195 | 196 | if(event_type == EPOLL_CTL_ADD){ 197 | 198 | if(fd_port_ori->wr_flag == false){ 199 | auto itre = fd_ports.begin(); // 如果是写,只需要获得已有的读的fd_port即可;如果是读,则是一个新的fd_port; 200 | for(; itre != fd_ports.end(); itre++){ 201 | if((*itre)->fd == fd_port_ori->fd){ 202 | break; 203 | } 204 | } 205 | if(itre != fd_ports.end()){ 206 | fd_port = (*itre); 207 | delete fd_port_ori; 208 | fd_port_ori = NULL; 209 | } 210 | } 211 | 212 | kevent_node = free_link->get_Node(); 213 | if(kevent_node == NULL){ 214 | return false; 215 | } 216 | 217 | kevent_node->fd = fd_port->fd; 218 | kevent_node->port = fd_port->port; 219 | kevent_node->handler = handler; // 应该为处理连接的函数 220 | kevent_node->c_response = response; 221 | if(read == 1){ 222 | ev.events = EPOLLIN|EPOLLRDHUP; 223 | } 224 | if(write == 1){ 225 | ev.events |= EPOLLOUT; // 写数据 226 | } 227 | 228 | }else if(event_type == EPOLL_CTL_MOD){ // 认为是修改,仅liunx有用,fd_port要进行预先的修改 229 | kevent_node = fd_port->event; 230 | if(read == 1){ 231 | ev.events |= (EPOLLIN|EPOLLRDHUP); 232 | kevent_node->handler = handler; // 应该为处理连接的函数 233 | } 234 | if(write == 1){ 235 | ev.events |= EPOLLOUT; // 写数据 236 | kevent_node->writehandler = handler; 237 | } 238 | kevent_node->c_response = response; 239 | }else{ // 认为是删除(实质上还是修改),但是此处的删除不同于epoll的删除,此处不删除,而是将对应操作的进行修改 240 | kevent_node = fd_port->event; 241 | truth_type = EPOLL_CTL_MOD; 242 | 243 | if(read == 1){ 244 | ev.events &= ~EPOLLIN; 245 | // kevent_node->handle = NULL; 246 | }else if(write == 1){ 247 | ev.events &= ~EPOLLOUT; 248 | // kevent_node->writehandler = NULL: 249 | } 250 | } 251 | if(kevent_node == NULL) {LOG_ERR(ERROR, "kevent_node = NULL, 说明出现了错误");} 252 | fd_port->event = kevent_node; 253 | 254 | ev.data.ptr = (void *)(kevent_node); 255 | 256 | if(epoll_ctl(kqueue_fd, truth_type, fd_port->fd, &ev) == -1){ 257 | if(truth_type == EPOLL_CTL_ADD) free_link->insert_Node(kevent_node); 258 | return false; 259 | } 260 | 261 | return true; 262 | } 263 | 264 | 265 | void CSocket::cia_del_epoll_linux(int fd, bool wr_flag){ 266 | if(fd < 1) return; 267 | 268 | auto itre = fd_ports.begin(); 269 | for(; itre != fd_ports.end(); itre++){ 270 | if((*itre)->fd == fd){ 271 | break; 272 | } 273 | } 274 | if(itre != fd_ports.end()){ 275 | if(wr_flag){ // 读删除的时候是真的删除,因为使用了EPOLLRDHUP 276 | // if((*itre)->event == NULL) {LOG_ERR(ERROR, "为什么这里是NULL");} 277 | if((*itre)->event != NULL) { 278 | free_link->insert_Node((*itre)->event); // 回收连接池 279 | // LOG_ERR(INFO, "这里没什么问题"); 280 | } 281 | (*itre)->event = NULL; 282 | delete (*itre); 283 | (*itre) = NULL; 284 | fd_ports.erase(itre); 285 | close(fd); 286 | }else{ // 写删除的时候只是把写给MOD了 287 | cia_operate_epoll_linux((*itre), 0, 1, NULL, NULL, EPOLL_CTL_DEL); 288 | } 289 | } 290 | } 291 | #endif 292 | 293 | #ifdef __APPLE__ 294 | // 删除一个文件描述符时,清楚掉该fd_ports的元素,将该fd_port放回到free_link 295 | void CSocket::cia_del_epoll_macos(int fd, bool wr_flag){ 296 | if(fd < 1) return; 297 | 298 | struct kevent kev2; 299 | 300 | auto itre = fd_ports.begin(); 301 | for(; itre != fd_ports.end(); itre++){ 302 | if((*itre)->fd == fd && (*itre)->wr_flag == wr_flag){ 303 | break; 304 | } 305 | } 306 | // LOG_ERR(WARN, "cia_del_epoll()是否出现错误:%d", itre == fd_ports.end()) 307 | 308 | if(itre != fd_ports.end()){ 309 | 310 | EV_SET(&kev2, fd, (*itre)->wr_flag?EVFILT_READ:EVFILT_WRITE, EV_DELETE, NULL, 0, (*itre)->event); 311 | kevent(kqueue_fd, &kev2, 1, NULL, 0, NULL); 312 | if((*itre)->event != NULL) free_link->insert_Node((*itre)->event); // 回收连接池 313 | 314 | (*itre)->event = NULL; 315 | delete (*itre); 316 | (*itre) = NULL; 317 | fd_ports.erase(itre); 318 | close(fd); 319 | } 320 | } 321 | 322 | 323 | // 添加一个文件描述符到kqueue中去,向fd_ports中加入一个,该函数并没有加,所以要在外面加,然后申请一个free_node 324 | // 参考accept,一定要在fd_ports中加入一条 325 | // read 表示读描述符,write表示写描述符,handler为回调函数 326 | bool CSocket::cia_add_epoll_macos(FD_PORT* fd_port, int read, int write, cia_event_handler_ptr handler, Response* response){ 327 | Kevent_Node* kevent_node = free_link->get_Node(); 328 | if(kevent_node == NULL){ 329 | return false; 330 | } 331 | 332 | // fd_ports.push_back(fd_port); 333 | 334 | kevent_node->fd = fd_port->fd; 335 | kevent_node->port = fd_port->port; 336 | kevent_node->handler = handler; // 应该为处理连接的函数 337 | kevent_node->c_response = response; 338 | 339 | fd_port->event = kevent_node; 340 | 341 | if(read == 1){ 342 | struct kevent kev1; 343 | EV_SET(&kev1, fd_port->fd, EVFILT_READ, EV_ADD | EV_ENABLE, NULL, 0, kevent_node); 344 | if(kevent(kqueue_fd, &kev1, 1, NULL, 0, NULL)<0){ 345 | free_link->insert_Node(kevent_node); 346 | return false; 347 | } 348 | } 349 | if(write == 1){ 350 | struct kevent kev2; 351 | EV_SET(&kev2, fd_port->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, NULL, 0, kevent_node); 352 | if(kevent(kqueue_fd, &kev2, 1, NULL, 0, NULL)<0){ 353 | free_link->insert_Node(kevent_node); 354 | return false; 355 | } 356 | } 357 | return true; 358 | } 359 | 360 | bool CSocket::epoll_init_macos(){ 361 | kqueue_fd = kqueue(); 362 | // LOG_ERR(INFO, "worker进程pid=%d中CSocket::epoll_init()设置成功!",getpid()) ; 363 | 364 | if(kqueue_fd == -1){ 365 | LOG_ERR(ERROR, "worker进程pid=%d中CSocket::epoll_init() 中 kqueue() 监听端口失败,直接退出!",getpid()) ; 366 | return false; 367 | } 368 | work_connection = CConfig::getInstance()->GetIntDefault("Worker_connection"); 369 | 370 | free_link = new FreeLink(work_connection); 371 | int er_judge = -1; 372 | for(int i=0; iwr_flag?1:0, fd_port->wr_flag?0:1, &CSocket::cia_socket_accept) == false){ 375 | er_judge = i; 376 | break; 377 | } 378 | } 379 | if(er_judge >= 0){ 380 | // 在这里面把内存释放了 381 | for(int i=0; ievent != NULL){ 384 | // fd_port->event->clear(); // 所有和event先关的删除操作要先通过一部clear。 385 | free_link->insert_Node(fd_port->event); 386 | // delete fd_port->event; 387 | fd_port->event = NULL; 388 | } 389 | } 390 | close(kqueue_fd); 391 | return false; 392 | } 393 | // 对所有监听端口添加到对应的ev中去 394 | // int sock = 1; 395 | // struct kevent ev; 396 | 397 | // EV_SET(&ev, sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 398 | // LOG_ERR(INFO, "worker进程pid=%d中CSocket::epoll_init()设置成功,函数退出!",getpid()) ; 399 | return true; 400 | // epoll_create(work_connection); // work_connection是指epoll红黑树的节点个数,大于0即可,实际上这个数字已经没有用了 401 | } 402 | #endif 403 | -------------------------------------------------------------------------------- /net/cia_socket.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_SOCKET_H__ 2 | #define __HEADERS_CIA_SOCKET_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "cia_conf.h" 11 | #include "cia_log.h" 12 | #include "cia_comm.h" 13 | #include "http_parser.h" 14 | #include "cia_parser.h" 15 | #include "cia_response_header.h" 16 | #ifdef __linux__ 17 | #include 18 | #else 19 | #include 20 | #define EPOLL_CTL_ADD 1 21 | #define EPOLL_CTL_DEL 2 22 | #define EPOLL_CTL_MOD 3 23 | 24 | #define EPOLLIN 1 25 | #define EPOLLOUT 4 26 | #define EPOLLRDHUP 8192 27 | #endif 28 | 29 | typedef class Kevent_Node Kevent_Node; 30 | 31 | typedef class CSocket CSocket; 32 | 33 | typedef void (CSocket::*cia_event_handler_ptr)(Kevent_Node* kn); //定义成员函数指针 34 | 35 | class Kevent_Node{ // 有两种,一种是request,另一种是response,所以如何设置这两种不同的类别 36 | public: 37 | int fd; // 描述符 38 | int port; // 端口号 39 | cia_event_handler_ptr handler; // 在linux下是:读事件的回调函数;在Mac下式读写事件的回调函数 40 | cia_event_handler_ptr writehandler; /// 仅在linux下有用,是写事件的回调函数 41 | 42 | Kevent_Node* next; 43 | 44 | Response* c_response; // 这里并没有删除c_response 45 | 46 | // char* buf; // 资源池,该连接发来的数据开辟的信息 47 | // int status; // 状态,数据有一定的格式; -1(PKG_UNUSE)表示连接池中的数据,0(PKG_INIT)表示已不在连接池中,1,2,3是其他的数据状态 48 | // long last_active; // 上次活跃时间 49 | 50 | // http_parser parser; // 表示这个要初始化 51 | CParser* c_message; //在哪里创建,在哪里删除 52 | 53 | 54 | Kevent_Node():fd(0), port(0), handler(NULL), writehandler(NULL), next(NULL), c_response(NULL){ 55 | // http_parser_init(&parser, HTTP_REQUEST); 56 | c_message = new CParser(); 57 | if(c_message == NULL){ 58 | LOG_ERR(ERROR, "空闲池中的数据区域Kevent_Node创建失败!"); 59 | exit(-2); 60 | } 61 | } 62 | Kevent_Node(int fd, cia_event_handler_ptr handler):fd(fd), port(0), handler(handler), writehandler(NULL), next(NULL), c_message(NULL), c_response(NULL){ 63 | // http_parser_init(&parser, HTTP_REQUEST); 64 | c_message = new CParser(); 65 | if(c_message == NULL){ 66 | LOG_ERR(ERROR, "空闲池中的数据区域Kevent_Node创建失败!"); 67 | exit(-2); 68 | } 69 | } 70 | ~Kevent_Node(){ 71 | clear(); 72 | delete c_message; 73 | } 74 | void clear(){ // 清理自己的数据,以放回到free_link时数据清除工作 75 | fd = 0; 76 | port = 0; 77 | handler = NULL; 78 | next = NULL; 79 | c_message->restore(); // 目的是清楚数据 80 | c_response = NULL; 81 | writehandler = NULL; 82 | // status = PKG_UNUSE; 83 | // http_parser_init(&parser, HTTP_REQUEST); 84 | } 85 | }; 86 | 87 | // 2019-3-22暂时未考虑多线程的情况,是否会用到多线程还未知,如果用到了的话会后续进行修改,一个典型的生产者消费者模型 88 | class FreeLink{ 89 | public: 90 | FreeLink():header(NULL), node_number(0){} 91 | ~FreeLink(){ // 析构 92 | while(header){ 93 | Kevent_Node* p = header; 94 | header = header->next; 95 | p->clear(); 96 | delete p; 97 | } 98 | } 99 | 100 | FreeLink(int n):node_number(n), header(NULL){ 101 | if(n <= 0) return; 102 | Kevent_Node* node1 = new Kevent_Node(); 103 | header = node1; 104 | Kevent_Node* p = node1; 105 | for(int i=1; inext = node_flag; 108 | p = p->next; 109 | } 110 | } 111 | Kevent_Node* get_Node(){ 112 | if(node_number <= 0) return NULL; 113 | Kevent_Node* res = header; 114 | header = header->next; 115 | 116 | node_number --; 117 | res->next = NULL; 118 | 119 | // res->last_active = time(0); // 活跃时间 120 | // res->status = PKG_INIT; // 状态变化,表示 121 | 122 | return res; 123 | } 124 | void insert_Node(Kevent_Node* node){ 125 | node->clear(); 126 | node->next = header; 127 | header = node; 128 | node_number ++; 129 | } 130 | private: 131 | std::atomic node_number;// 当前FreeLink中有多少个空闲链 132 | Kevent_Node* header; // 头结点 133 | }; 134 | // TODO 要加一个字段,是读还是写 135 | class FD_PORT{ 136 | public: 137 | int fd; // 描述符 138 | int port; // 对应的监听端口 139 | bool wr_flag; // 读写标记,因为kqueue自身是分离读和写的,所以要加上这个标记, 读是True(linux下读是true,即可读又可写也是True), 写是false 140 | Kevent_Node* event; //处理该描述符相关 的区域 141 | FD_PORT(int fd, bool wr_flag, int port):fd(fd),port(port),wr_flag(wr_flag), event(NULL){} 142 | }; 143 | 144 | class CSocket{ 145 | public: 146 | CSocket(); 147 | ~CSocket(); 148 | 149 | bool setnoneblocking(int fd); 150 | 151 | bool socket_init(); 152 | void closesocket(); // 关闭文件描述符,以及清楚fd_ports对应的内存 153 | 154 | // epoll_init()初始化失败的话返回false,直接退出子进程,当某个子进程退出的时候,应该再创建一个 155 | bool epoll_init(); //epoll的使用是linux only 而 macos是unix-like的,所以使用的是kqueue; 156 | 157 | #ifdef __linux__ 158 | bool epoll_init_linux();// 创建epoll ;主要三个函数 epoll_create(), epoll_ctl() 和 epoll_wait(); 这里使用epoll_create(); 159 | bool cia_operate_epoll_linux(FD_PORT* fd_port_ori, int read, int write, cia_event_handler_ptr handler, Response* response=NULL, uint32_t event_type=EPOLL_CTL_ADD); 160 | void cia_del_epoll_linux(int fd, bool wr_flag); 161 | void cia_epoll_process_events_linux(const struct timespec *timeout = NULL); 162 | #elif __APPLE__ 163 | bool epoll_init_macos(); 164 | bool cia_add_epoll_macos(FD_PORT* fd_port, int read, int write, cia_event_handler_ptr handler, Response* response=NULL); 165 | void cia_del_epoll_macos(int fd, bool wr_flag); 166 | void cia_epoll_process_events_macos(const struct timespec *timeout = NULL); 167 | #endif 168 | 169 | 170 | bool cia_add_epoll(FD_PORT* fd_port, int read, int write, cia_event_handler_ptr handler, Response* response=NULL, uint32_t event_type=EPOLL_CTL_ADD); 171 | void cia_del_epoll(int fd, bool wr_flag); 172 | void cia_socket_accept(Kevent_Node* kn); 173 | void cia_epoll_process_events(const struct timespec *timeout = NULL); 174 | 175 | void cia_wait_request_handler(Kevent_Node* kn); // 处理发来的请求de回调函数 176 | void cia_wait_responese_handler(Kevent_Node* kn); // 回复请求的回调函数 177 | 178 | void sendResponse(Response* res); // 发送请求 179 | void porcRequest(Message* message); // 处理request 180 | 181 | private: 182 | // 三件套,当多了一个需要处理的文件描述符时,需要将一个对应的FD_PORT添加到fd_ports中去,current_link需要+1,free_link需要getNode()一次 183 | // 当关闭一个文件描述符时, 需要删除一个fd_ports 184 | // 当前kqueue或者epollI/O多路复用的数量 = 监听端口描述+已连接的描述符数量,大小应该等于fd_ports.size(); 185 | std::vector fd_ports; //当前连接数量,不止是fd+ports, 建立连接后的文件描述符也要存在这里,他的大小表示当前连接的数量。 186 | FreeLink* free_link; 187 | 188 | int kqueue_fd; // 建立起的kqueuq的文件描述符 189 | // struct kevent* kevents; // 希望后续不会因为多线程的问题而导致出现问题 190 | int work_connection; // epoll支持的最大连接数量, 191 | 192 | /** 193 | * 针对静态资源请求的函数 194 | * */ 195 | // ---- 为构造response服务的函数 ------- 196 | std::string GetContentType(const std::string& url); 197 | void getRequestHeader(Message* message, Cia_Response_Header* header); 198 | int GetFile(Message* message, Cia_Response_Header* header); 199 | 200 | void ConstructResponseStatic(Message* message); 201 | void ConstructResponseRestful(Message* message); 202 | void ConstructResponseOther(Message* message); 203 | 204 | void ConstructResponse(Message* message); 205 | // ----------------------------------- 206 | 207 | // ---- 为sendResponse服务的函数 ------- 208 | int sendBuf(Response* res); 209 | int sendFile(Response* res); 210 | int sendProc(Response* res); 211 | void closeFile(Response* res, int fd); 212 | // ------------------------------------ 213 | 214 | 215 | /** 216 | * 针对业务处理的函数 217 | * */ 218 | // 处理POST消息 219 | bool prcoPost(Message* message); 220 | 221 | bool parsePostBody(Message* message, const std::string& body, const std::string& boundry); 222 | // 输入参数表示HTTPbody值和Block位置的[begin, end) 223 | bool parsePostBlock(Message* message, const std::string& body, int begin, int end); 224 | // 处理Body里的block的header 225 | void procBodyHeader(const char* body_header, int body_header_l, std::string& name, std::string& filename); 226 | 227 | }; 228 | 229 | #endif -------------------------------------------------------------------------------- /net/cia_socket_accept.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_socket.h" 2 | // 存在惊群效应 3 | void CSocket::cia_socket_accept(Kevent_Node* kn){ 4 | // accept 也是要设置为非阻塞的,且建立完一个连接就要把这个连接加入到epoll中去 5 | struct sockaddr_in client_addr; 6 | socklen_t len = sizeof(client_addr); 7 | 8 | int accept_fd = accept(kn->fd, (struct sockaddr *)&client_addr, &len); 9 | 10 | if(accept_fd == -1){ // 这里有多种情况 11 | int err = errno; 12 | if(err == EAGAIN || err == EWOULDBLOCK){ // 再试一次,不算错误 13 | return; 14 | } 15 | if (err == ECONNABORTED) //ECONNRESET错误则发生在对方意外关闭套接字后【您的主机中的软件放弃了一个已建立的连接--由于超时或者其它失败而中止接连(用户插拔网线就可能有这个错误出现)】 16 | { 17 | //该错误被描述为“software caused connection abort”,即“软件引起的连接中止”。原因在于当服务和客户进程在完成用于 TCP 连接的“三次握手”后, 18 | //客户 TCP 却发送了一个 RST (复位)分节,在服务进程看来,就在该连接已由 TCP 排队,等着服务进程调用 accept 的时候 RST 却到达了。 19 | //POSIX 规定此时的 errno 值必须 ECONNABORTED。源自 Berkeley 的实现完全在内核中处理中止的连接,服务进程将永远不知道该中止的发生。 20 | //服务器进程一般可以忽略该错误,直接再次调用accept。 21 | LOG_ERR(ERROR, "cia_socket_accept() 中的 accpet()出现错误errno = ECONNABORTED, 直接返回"); 22 | } 23 | else if (err == EMFILE || err == ENFILE) //EMFILE:进程的fd已用尽【已达到系统所允许单一进程所能打开的文件/套接字总数】。可参考:https://blog.csdn.net/sdn_prc/article/details/28661661 以及 https://bbs.csdn.net/topics/390592927 24 | //ulimit -n ,看看文件描述符限制,如果是1024的话,需要改大; 打开的文件句柄数过多 ,把系统的fd软限制和硬限制都抬高. 25 | //ENFILE这个errno的存在,表明一定存在system-wide的resource limits,而不仅仅有process-specific的resource limits。按照常识,process-specific的resource limits,一定受限于system-wide的resource limits。 26 | { 27 | 28 | LOG_ERR(ERROR, "cia_socket_accept() 中的 accpet()出现错误errno = EMFILE | ENFILE, 直接返回"); 29 | } 30 | return; 31 | } 32 | if(!setnoneblocking(accept_fd)){ 33 | close(accept_fd); 34 | LOG_ERR(ERROR, "CSocket::cia_socket_accept() 中 setnoneblocking() 设置非阻塞失败,直接退出!"); 35 | return; 36 | } 37 | 38 | int current_link = fd_ports.size(); 39 | FD_PORT* fd_port = new FD_PORT(accept_fd,true, 0); 40 | 41 | // TODO 处理连接请求发来的数据 42 | if(cia_add_epoll(fd_port, fd_port->wr_flag?1:0, fd_port->wr_flag?0:1, &CSocket::cia_wait_request_handler) == false){ 43 | if(fd_port != NULL) delete fd_port; 44 | return; 45 | } 46 | if(fd_port != NULL) fd_ports.push_back(fd_port); 47 | 48 | // accept_fd 说明连接已经建立,要将该连接加入到kevent里面去 49 | } -------------------------------------------------------------------------------- /net/cia_socket_http.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "cia_socket.h" 9 | #include "cia_global.h" 10 | // 根据请求的url地址,构造 response 的返回格式 content-type 11 | std::string CSocket::GetContentType(const std::string& url){ 12 | // 针对restful api 请求 13 | if(url.find_last_of('.') == std::string::npos) return "application/json;charset=UTF-8"; 14 | 15 | std::string suffixStr = url.substr(url.find_last_of('.') + 1);//获取文件后缀 16 | 17 | transform(suffixStr.begin(), suffixStr.end(), suffixStr.begin(), ::tolower); 18 | 19 | return CConfig::getInstance()->GetMime(suffixStr); 20 | 21 | } 22 | 23 | // 通过request header 来构造response header 的部分内容 24 | void CSocket::getRequestHeader(Message* message, Cia_Response_Header* header){ 25 | std::string UserAgent; // 用户信息 26 | std::string Connection; // 连接状态 27 | std::string IfModifiedSince = "no"; // 改变? 28 | 29 | for(auto itre = (message->headers).begin(); itre != (message->headers).end(); itre++){ 30 | if((*itre)[0] == "User-Agent"){ 31 | UserAgent = (*itre)[1]; 32 | }else if((*itre)[0] == "Connection"){ 33 | Connection = (*itre)[1]; 34 | }else if((*itre)[0] == "If-Modified-Since"){ 35 | IfModifiedSince = (*itre)[1]; 36 | } 37 | } 38 | std::string log_access = message->url + " " + UserAgent; 39 | LOG_ACC(INFO, log_access.c_str()); 40 | 41 | if(Connection.length() > 0){ 42 | header->Connection = Connection; 43 | }else{ 44 | header->Connection = "close"; 45 | } 46 | 47 | if(header->Last_Modified == IfModifiedSince){ 48 | header->code = "304"; 49 | header->code_ds = "Not Modified"; 50 | header->Content_Length = "0"; 51 | }else{ 52 | header->code = "200"; 53 | header->code_ds = "OK"; 54 | header->Content_Type = GetContentType(message->url); 55 | } 56 | } 57 | 58 | // 根据静态资源构造响应头; 59 | // 如果资源存在并正确打开,则返回文件句柄;否则返回404.html的文件句柄 60 | int CSocket::GetFile(Message* message, Cia_Response_Header* header){ 61 | // 根据请求的url和location得到静态资源地址 62 | std::string path = CConfig::getInstance()->GetPath(message->url); 63 | if(path.length() == 0){ 64 | LOG_ACC(ERROR, "CSocket::GetFile() 匹配静态资源地址失败,没有匹配到任何静态资源地址。"); 65 | return -1; 66 | } 67 | 68 | struct stat buf; 69 | 70 | int filedesc = open(path.c_str(), O_RDONLY); 71 | if(stat(path.c_str(), &buf) == -1 || filedesc == -1){ 72 | int err = errno; 73 | LOG_ACC(INFO, "打开文件path = %s 出现错误,errno = %d", path.c_str(), err); 74 | header->code = "404"; 75 | header->code_ds = "Not Found"; // 这里要返回404的html 76 | 77 | path = CConfig::getInstance()->GetPath("/404.html"); 78 | if(path.length() == 0){ 79 | LOG_ACC(ERROR, "CSocket::GetFile() 匹配静态资源404.html 地址失败,没有匹配到任何静态资源地址。"); 80 | return -1; 81 | } 82 | 83 | if(filedesc != -1) close(filedesc); 84 | filedesc = open(path.c_str(), O_RDONLY); 85 | if(stat(path.c_str(), &buf) == -1 || filedesc == -1){ 86 | LOG_ACC(INFO, "打开404.html文件出现错误,errno = %d", path.c_str(), err); 87 | if(filedesc != -1) close(filedesc); 88 | return -1; 89 | } 90 | header->Content_Type = GetContentType("/404.html"); 91 | header->Content_Length = std::to_string(buf.st_size); 92 | header->Last_Modified = GetGmtTime(&(buf.st_mtime)); 93 | }else{ 94 | header->Last_Modified = GetGmtTime(&(buf.st_mtime)); 95 | header->Content_Length = std::to_string(buf.st_size); 96 | getRequestHeader(message, header); 97 | } 98 | 99 | return filedesc; 100 | } 101 | 102 | void CSocket::ConstructResponseStatic(Message* message){ 103 | Cia_Response_Header header; 104 | int filedesc = GetFile(message, &header); 105 | 106 | if(filedesc != -1){ 107 | if(header.code == "304"){ 108 | close(filedesc); 109 | filedesc = -1; 110 | } 111 | } 112 | 113 | std::string value = header.getHeader(); 114 | char* buffer = new char[value.length() + 2]; 115 | strcpy(buffer, value.c_str()); 116 | 117 | Response* response = new Response(buffer, strlen(buffer)); 118 | 119 | int fd = message->fd; 120 | response->fd = fd; 121 | 122 | if(filedesc != -1){ 123 | response->file_list.push_back(filedesc); 124 | } 125 | 126 | datapoll.inResQueue(response); 127 | } 128 | 129 | void CSocket::ConstructResponseRestful(Message* message){ 130 | Cia_Response_Header header; 131 | 132 | // 构造 response的 Code, Code_ds, Content_Type, Connection 133 | getRequestHeader(message, &header); 134 | header.Last_Modified = ""; 135 | 136 | std::string body = "{ \ 137 | \"msg\": \"Success\", \ 138 | \"code\": 200, \ 139 | \"data\": [ \ 140 | \"请求成功.\" \ 141 | ] \ 142 | }"; 143 | header.Content_Length = std::to_string(body.length()); 144 | 145 | std::string value = header.getHeader(); 146 | char* buffer = new char[value.length() + body.length() + 2]; 147 | strcpy(buffer, value.c_str()); 148 | strcpy(buffer+value.length(), body.c_str()); 149 | 150 | Response* response = new Response(buffer, strlen(buffer)); 151 | 152 | LOG_ERR(DEBUG, "发送的响应数据为:%s", response->begin); 153 | int fd = message->fd; 154 | response->fd = fd; 155 | 156 | datapoll.inResQueue(response); 157 | } 158 | 159 | void CSocket::ConstructResponseOther(Message* message){ 160 | ConstructResponseStatic(message); // 其他目前也先按照静态资源请求的方式来处理 161 | } 162 | 163 | /** 164 | * 构造response信息。 165 | * 备注:response有两种,一种是静态资源请求的response信息,另一种是RestFul API请求的response信息。 166 | * 如何筛选出这两种请求: 通过函数CConfig::getInstance()->RequestType(string& url) 167 | * */ 168 | // 在这里判断 是 静态资源请求 还是 RESTFul Api 请求 169 | void CSocket::ConstructResponse(Message* message){ 170 | 171 | int request_type = CConfig::getInstance()->RequestType(message->url); 172 | 173 | if(request_type == 0){ // 静态资源请求 174 | ConstructResponseStatic(message); 175 | }else if(request_type == 1){ // RestFul Api 请求 176 | ConstructResponseRestful(message); 177 | }else{ 178 | ConstructResponseOther(message); 179 | } 180 | 181 | } -------------------------------------------------------------------------------- /net/cia_socket_operator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "cia_socket.h" 10 | #include "cia_comm.h" 11 | 12 | #include "cia_response_header.h" 13 | 14 | typedef unsigned char BYTE; 15 | int CSocket::sendBuf(Response* res){ 16 | int n; 17 | for(;;){ 18 | 19 | n = send(res->fd, res->begin, res->left_len, 0); 20 | // LOG_ERR(INFO, "发送数据大小为:%d", n); 21 | if(n > 0){ 22 | return n; 23 | } 24 | 25 | if(n == 0){ // 表示客户端主动断开连接 26 | return 0; 27 | } 28 | 29 | int err = errno; 30 | 31 | if(err == EAGAIN || err == EWOULDBLOCK){ 32 | return -1; 33 | } 34 | if(err == EINTR){ 35 | ; 36 | }else{ 37 | return -2; 38 | } 39 | } 40 | } 41 | // 关闭fd文件,并将其从res中取出 42 | void CSocket::closeFile(Response* res, int fd){ 43 | if(fd <= 0) return; 44 | 45 | if(close(fd) == -1){ 46 | LOG_ACC(ERROR, "CSocket::sendFile()函数在关闭文件时出现错误"); 47 | } 48 | res->file_list.pop_front(); 49 | } 50 | // 返回值:n 51 | // n > 0 表示成功发送多少数据; 52 | // n == 0 表示客户端关闭连接 53 | // n == -1 表示EAGAIN或者EWOULDBLOCK,发送缓冲区满,等会再试 54 | // n == -2 表示发送出现错误 55 | // n == -3 表示上一个文件发送完成了,继续发送下一个文件 56 | int CSocket::sendFile(Response* res){ 57 | int fn; 58 | int NBYTES = 2048; 59 | 60 | for(;;){ 61 | char* buf = new char[NBYTES]; // delete []buf; 62 | memset(buf, 0, NBYTES); 63 | int file = (res->file_list).front(); 64 | fn = read(file, (void *)buf, NBYTES); 65 | if(fn == 0){ 66 | //表示该文件已经读取到末尾,无需再继续读取了;close文件, 并弹出 67 | delete []buf; 68 | closeFile(res, file); 69 | return -3; // 表示该文件已经发送完毕了,通知sendProc处理下一个文件 70 | }else if(fn == -1){ // read文件可能出现的错误 71 | int err = errno; 72 | 73 | switch (err) 74 | { 75 | case EINTR: 76 | //被信号打断,不用管,继续,因为会走for循环,重新读取 77 | break; 78 | case EAGAIN: 79 | // 当前没有数据可读,等会再试 80 | delete []buf; 81 | return -1; 82 | break; 83 | case EIO: 84 | LOG_ACC(ERROR, "CSocket::sendFile()函数read文件时遇到EIO错误"); 85 | delete []buf; 86 | closeFile(res, file); 87 | return -2; 88 | break; 89 | case EISDIR: 90 | LOG_ACC(ERROR, "CSocket::sendFile()函数read文件时遇到EISDIR错误,读取的文件是一个目录"); 91 | delete []buf; 92 | closeFile(res, file); 93 | return -2; 94 | break; 95 | case EBADF: 96 | LOG_ACC(ERROR, "CSocket::sendFile()函数read文件时遇到EBADF错误,读取的文件不是一个合法文件"); 97 | delete []buf; 98 | closeFile(res, file); 99 | return -2; 100 | break; 101 | case EINVAL: 102 | LOG_ACC(ERROR, "CSocket::sendFile()函数read文件时遇到EINVAL错误,文件不可读"); 103 | delete []buf; 104 | closeFile(res, file); 105 | return -2; 106 | break; 107 | default: 108 | LOG_ACC(ERROR, "CSocket::sendFile()函数read文件时遇到未知错误:errno=%d,读取文件出错", err); 109 | delete []buf; 110 | closeFile(res, file); 111 | return -2; 112 | break; 113 | } 114 | }else{ 115 | res->msg = buf; 116 | res->begin = buf; 117 | res->left_len = fn; 118 | return sendBuf(res); 119 | } 120 | } 121 | } 122 | // 返回值:n 123 | // n > 0 表示成功发送多少数据; 124 | // n == 0 表示客户端关闭连接 125 | // n == -1 表示EAGAIN或者EWOULDBLOCK,发送缓冲区满,等会再试 126 | // n == -2 表示发送出现错误 127 | // n == -3 表示文件已经全部发送完了, 发送结束 128 | int CSocket::sendProc(Response* res){ 129 | int n; 130 | for(;;){ 131 | // 判断是否发送完成缓冲区文件 132 | if(!res->msg_finished){ 133 | return sendBuf(res); 134 | }else{ 135 | if(res->file_list.empty()){ 136 | return -3; 137 | } 138 | n = sendFile(res); 139 | if(n == -3){ 140 | continue; 141 | } 142 | return n; 143 | } 144 | } 145 | } 146 | 147 | // 和recv是对应着的 148 | // 返回值 >0表示发送对应大小的数据, 0表示客户端断开, -1 表示缓冲区满, -2表示出错;当收到返回值>0和-1时需要考虑加入到epoll写中,此外-2表示出错,0表示断开连接,析构; 149 | void CSocket::sendResponse(Response* res){ 150 | // LOG_ACC(INFO, "------发送数据-------"); 151 | for(;;){ 152 | int n = sendProc(res); 153 | if(n > 0){ 154 | if(n >= res->left_len){ //msg中的数据发完了 155 | res->msg_finished = true; 156 | // delete [](res->msg); 157 | res->msg = NULL; 158 | res->begin = NULL; 159 | res->left_len = -1; 160 | // LOG_ACC(INFO, "走到这:下一步"); 161 | continue; 162 | }else{ 163 | res->left_len -= n; 164 | res->begin += n; 165 | if(res->send_count == 0){ 166 | LOG_ACC(INFO, "----尚未发送完整, 放到epoll中去-----"); 167 | // 加入到epoll中去 168 | // add epolll 169 | FD_PORT* fd_port = new FD_PORT(res->fd, false, 0); 170 | if(cia_add_epoll(fd_port, fd_port->wr_flag?1:0, fd_port->wr_flag?0:1, &CSocket::cia_wait_responese_handler, res, EPOLL_CTL_MOD) == false){ 171 | if(fd_port != NULL) delete fd_port; 172 | LOG_ACC(ERROR, "CSocket::sendResponse() 中向epoll中添加节点时出错[n>0]"); 173 | return; 174 | } 175 | if(fd_port != NULL) fd_ports.push_back(fd_port); 176 | else{LOG_ACC(INFO, "SEND的时候确实吧fd_port删掉了");} 177 | } 178 | ++res->send_count; 179 | } 180 | }else if(n == -1){ 181 | if(res->send_count == 0){ 182 | LOG_ACC(INFO, "----尚未发送完整, 放到epoll中去-----"); 183 | // 加入到epoll中去 184 | // add epoll 185 | FD_PORT* fd_port = new FD_PORT(res->fd, false, 0); 186 | if(cia_add_epoll(fd_port, fd_port->wr_flag?1:0, fd_port->wr_flag?0:1, &CSocket::cia_wait_responese_handler, res, EPOLL_CTL_MOD) == false){ 187 | if(fd_port != NULL) delete fd_port; 188 | LOG_ACC(ERROR, "CSocket::sendResponse() 中向epoll中添加节点时出错[n==-1]"); 189 | return; 190 | } 191 | if(fd_port != NULL) fd_ports.push_back(fd_port); 192 | } 193 | ++res->send_count; 194 | }else if(n == -3){ 195 | if(res->send_count > 0){ // 表示加入到epoll中去了,要删掉 196 | // delete from epoll; 197 | LOG_ACC(INFO, "------发送完成, 准备回收------"); 198 | cia_del_epoll(res->fd, false); 199 | } 200 | // LOG_ACC(INFO, "------发送完成------"); 201 | delete res; 202 | }else{ 203 | if(res->send_count > 0){ 204 | cia_del_epoll(res->fd, false); 205 | } 206 | delete res; 207 | } 208 | break; 209 | } 210 | } 211 | 212 | // recv 213 | void CSocket::porcRequest(Message* message){ 214 | // LOG_ACC(INFO,"线程threadid = %d 开始处理消息",std::this_thread::get_id()); 215 | 216 | LOG_ACC(INFO, "----------消息全文-----------"); 217 | LOG_ACC(INFO, message->url.c_str()); 218 | LOG_ACC(INFO, std::to_string(message->method).c_str()); 219 | 220 | bool pro_succ = true; 221 | switch ( message->method ) { 222 | case 1: // GET 223 | ConstructResponse(message); //构造响应,HTTP 处理方式; 224 | break; 225 | case 3: // POST 226 | pro_succ = prcoPost(message); // 尚未增加响应 227 | if(!pro_succ){ 228 | LOG_ACC(ERROR, "CSocket::porcRequest() %s Post 请求解析出现错误!", message->url.c_str()); 229 | } 230 | ConstructResponse(message); //构造响应,HTTP 处理方式; 目前是静态资源服务器 231 | break; 232 | default: 233 | break; 234 | } 235 | 236 | 237 | // 打印request消息头 238 | // for(int i=0; iheaders.size(); i++){ 239 | // std::string line; 240 | // for(auto x:message->headers[i]){ 241 | // line += x + " "; 242 | // } 243 | // LOG_ACC(INFO, line.c_str()); 244 | // } 245 | // LOG_ACC(INFO, "-------body---------"); 246 | // LOG_ACC(INFO, "接收到的数据大小:%d", (message->body.length())); 247 | 248 | // 打印request消息包 249 | // LOG_ACC(INFO, message->body.c_str()); 250 | 251 | // int method = message->method; //GET or POST or OTHERS 252 | delete message; 253 | } 254 | -------------------------------------------------------------------------------- /net/cia_socket_post.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "cia_socket.h" 6 | #include "cia_comm.h" 7 | 8 | #include "cia_response_header.h" 9 | 10 | bool CSocket::prcoPost(Message* message){ 11 | // for(int i=0; iheaders.size(); i++){ 12 | // LOG_ACC(INFO, "%d+++++%s:%s",i, message->headers[i][0].c_str(), message->headers[i][1].c_str()); 13 | // } 14 | // for(auto itre = message->header_map.begin(); itre != message->header_map.end(); itre++){ 15 | // LOG_ACC(INFO, "header_map++++:%s: %d", itre->first.c_str(), itre->second); 16 | // } 17 | std::string content_type = message->headers[message->header_map["Content-Type"]][1]; 18 | 19 | LOG_ACC(INFO, "contenr_type 的类型值是: %s", content_type.c_str()); 20 | std::string cont; 21 | int pike = content_type.find_first_of(";"); 22 | if( pike != std::string::npos){ 23 | cont = content_type.substr(0, content_type.find_first_of(";")); 24 | }else{ 25 | cont = content_type; 26 | } 27 | if(cont == "multipart/form-data"){ 28 | std::string boundry = "--" + content_type.substr(content_type.find_last_of("=")+1); 29 | return parsePostBody(message, message->body, boundry); 30 | }else if(cont == "application/json"){ 31 | return false; 32 | }else{ 33 | return false; 34 | } 35 | 36 | } 37 | 38 | 39 | /** 40 | * 处理Contetn-Type:multipart/form-data 的 POST 数据包体 41 | * */ 42 | bool CSocket::parsePostBody(Message* message, const std::string& body, const std::string& boundry){ 43 | int count = 0, count2 = 0; 44 | int boundry_length = boundry.length() + 2; // 因为每一行结尾是有 ”\r\n“的 45 | 46 | int block_end = body.find(boundry, 0); 47 | int block_begin = block_end + boundry_length; // 因为还有个换行符 48 | while(block_end != std::string::npos && block_begin < body.length()){ 49 | block_end = body.find(boundry, block_begin); 50 | if(block_end == std::string::npos){ 51 | break; 52 | }else{ 53 | // block = body.substr(block_begin, block_end - block_begin); 54 | // 此处 body中的每一块(称为block的位置为 [block_begin,block_end)) 55 | // 整理可以针对每一个block进行处理 56 | if(!parsePostBlock(message, body, block_begin, block_end)){ 57 | return false; 58 | } 59 | 60 | block_begin = block_end + boundry_length; // 因为还有个换行符 61 | } 62 | } 63 | return true; 64 | } 65 | 66 | // 输入参数表示HTTPbody值和Block位置的[begin, end) 67 | bool CSocket::parsePostBlock(Message* message, const std::string& body, int begin, int end){ 68 | /** 69 | * body_header 为每个block 的消息头部描述信息的指针 70 | * body_body 为每个block的消息内容的指针 71 | * body_header_l 为 body_header 的长度 72 | * body_bodt_l 为 body_body 的长度 73 | * */ 74 | // std::map post_body; // 存结果,这里好像似乎应该存成一个全局的值 ?? 75 | 76 | const char* body_header = body.c_str() + begin; 77 | const char* body_body; 78 | 79 | int body_header_l = 0, body_body_l = 0; 80 | 81 | int body_header_end_index = body.find("\r\n\r\n", begin); 82 | 83 | if(body_header_end_index != std::string::npos){ 84 | 85 | body_header_l = body_header_end_index - begin; 86 | body_body = body.c_str() + body_header_end_index + 4; 87 | body_body_l = end - (body_header_end_index + 4); 88 | 89 | std::string name, filename; 90 | procBodyHeader(body_header, body_header_l, name, filename); 91 | 92 | if(filename.length() > 0){ // 说明是file 93 | FILE* png_file = fopen(filename.c_str(), "w"); 94 | if(png_file == NULL){ 95 | LOG_ACC(ERROR, "CSocket::parsePostBlock() 中 文件filename = %s 打开失败!", filename.c_str()); 96 | return false; 97 | }else{ 98 | int write_n = fwrite(body_body, sizeof(unsigned char), body_body_l, png_file); 99 | if(write_n == body_body_l){ 100 | LOG_ACC(INFO, "CSocket::parsePostBlock() 中 文件filename = %s 写成功!", filename.c_str()); 101 | }else{ 102 | LOG_ACC(INFO, "CSocket::parsePostBlock() 中 文件filename = %s 没写完整!", filename.c_str()); 103 | if(fclose(png_file) == EOF){ 104 | LOG_ACC(INFO, "CSocket::parsePostBlock() 中关闭 文件filename = %s 时出现错误", filename.c_str()); 105 | } 106 | return false; 107 | } 108 | } 109 | if(fclose(png_file) == EOF){ 110 | LOG_ACC(INFO, "CSocket::parsePostBlock() 中关闭 文件filename = %s 时出现错误", filename.c_str()); 111 | } 112 | 113 | (message->post_body)[name] = filename; 114 | // post_body[name] = filename; 115 | }else{ // 说明不是file 116 | (message->post_body)[name] = std::string(body_body, body_body_l); 117 | } 118 | 119 | // LOG_ACC(INFO, "打印message->post_body[%s] = %s", name.c_str(), filename.c_str()); 120 | // FILE* png_file = fopen("./arch.png", "w"); 121 | // if(png_file == NULL){ 122 | // return false; 123 | // }else{ 124 | // int write_n = fwrite(body_body, sizeof(unsigned char), body_body_l, png_file); 125 | // if(write_n == body_body_l){ 126 | // LOG_ACC(INFO, "写成了"); 127 | // }else{ 128 | // LOG_ACC(INFO, "没写成"); 129 | // } 130 | // } 131 | // if(fclose(png_file) == EOF){ 132 | // LOG_ACC(INFO, "关闭文件时出现错误"); 133 | // } 134 | return true; 135 | } 136 | return false; 137 | } 138 | 139 | void CSocket::procBodyHeader(const char* body_header, int body_header_l, std::string& name, std::string& filename){ 140 | // 示例值: 141 | // Content-Disposition: form-data; name="anothers"; filename="Arch.png" 142 | // Content-Type: image/png 143 | 144 | // Content-Disposition: form-data; name="anothers" 145 | std::string header(body_header, body_header_l); 146 | 147 | LOG_ACC(DEBUG, "header信息:%s", header.c_str()); 148 | int name_begin = header.find("name=\"") + 6; 149 | int name_end = header.find("\"", name_begin); 150 | if(name_begin != std::string::npos){ 151 | if(name_end != std::string::npos){ 152 | name = header.substr(name_begin, name_end-name_begin); 153 | }else{ 154 | name = header.substr(name_begin); 155 | } 156 | }else{ 157 | name = ""; 158 | filename = ""; 159 | return; 160 | } 161 | 162 | LOG_ACC(INFO, "name = %s", name.c_str()); 163 | 164 | int file_name_begin = header.find("filename=\"", name_begin); 165 | if(file_name_begin != std::string::npos){ 166 | file_name_begin += 10; 167 | int file_name_end = header.find('"', file_name_begin); 168 | if(file_name_end != std::string::npos){ 169 | filename = header.substr(file_name_begin, file_name_end - file_name_begin); 170 | }else{ 171 | filename = header.substr(file_name_begin); 172 | } 173 | }else{ 174 | filename = ""; 175 | } 176 | LOG_ACC(INFO, "filename = %s", filename.c_str()); 177 | 178 | } -------------------------------------------------------------------------------- /net/cia_socket_process.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_socket.h" 2 | 3 | void CSocket::cia_epoll_process_events(const struct timespec *timeout){ 4 | #ifdef __linux__ // linux操作系统 epoll 5 | cia_epoll_process_events_linux(timeout); 6 | #elif __APPLE__ // macos操作系统 kqueue 7 | cia_epoll_process_events_macos(timeout); 8 | #else 9 | return ; 10 | #endif 11 | } 12 | 13 | #ifdef __linux__ 14 | void CSocket::cia_epoll_process_events_linux(const struct timespec *timeout){ 15 | 16 | struct epoll_event events[work_connection]; 17 | int nevents = 0; 18 | nevents = epoll_wait(kqueue_fd, events, work_connection, -1); 19 | if(nevents < 0){ 20 | // 一堆判断条件先不管 21 | LOG_ERR(ERROR, "CSocket::cia_epoll_process_events()的epoll_wait()返回值为负数,出错了!"); 22 | return; 23 | } 24 | for(int i=0; i*(eve->handler))(eve); 27 | } 28 | } 29 | #endif 30 | #ifdef __APPLE__ 31 | void CSocket::cia_epoll_process_events_macos(const struct timespec *timeout){ 32 | struct kevent events[work_connection]; 33 | int nevents = 0; 34 | 35 | nevents = kevent(kqueue_fd, NULL, 0, events, work_connection, timeout); 36 | 37 | if(nevents < 0){ 38 | // 一堆判断条件先不管 39 | LOG_ERR(ERROR, "CSocket::cia_epoll_process_events()中kevent()返回值为负数,出错了!"); 40 | return; 41 | } 42 | 43 | for(int i = 0; i*(eve->handler))(eve); 47 | } 48 | } 49 | #endif -------------------------------------------------------------------------------- /net/cia_socket_request.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_socket.h" 2 | #include "cia_global.h" 3 | 4 | #define DATA_LEN 20 5 | static size_t MAX_IOSTREAM_ELEMENT = 2000; 6 | void CSocket::cia_wait_request_handler(Kevent_Node* kn){ 7 | // LOG_ERR(INFO, "pid = %d 来了数据了来了数据了", getpid()); 8 | char buffer[MAX_IOSTREAM_ELEMENT]; 9 | memset(buffer, 0, MAX_IOSTREAM_ELEMENT); 10 | int n = recv(kn->fd, buffer, MAX_IOSTREAM_ELEMENT-1, 0); 11 | if(n == 0){ // 表示客户端断开了连接 12 | //断开连接 13 | LOG_ERR(WARN, "断开连接"); 14 | cia_del_epoll(kn->fd, true); 15 | return; 16 | } 17 | if(n < 0){ 18 | int err = errno; 19 | if(err == EAGAIN || err == EWOULDBLOCK){// 不算错误 20 | LOG_ERR(WARN,"收到EAGAIN"); 21 | return; 22 | } 23 | if(err == EINTR){ 24 | LOG_ERR(WARN, "收包被信号打断"); 25 | return; 26 | } 27 | if(err == ECONNRESET){ // 客户端强行关闭 28 | LOG_ERR(WARN, "客户端强行关闭"); 29 | }else{ 30 | LOG_ERR(WARN, "打印看看出现什么错误:err=%d", err); 31 | } 32 | cia_del_epoll(kn->fd, true); 33 | return; 34 | } 35 | 36 | // LOG_ERR(INFO, "收到数据:%s", buffer); 37 | size_t nparsed = kn->c_message->parser_execute(buffer, n); 38 | 39 | if (nparsed != (size_t)n) { 40 | LOG_ACC(ERROR, 41 | "Error: %s (%s)\n", 42 | http_errno_description(HTTP_PARSER_ERRNO(&(kn->c_message->parser))), 43 | http_errno_name(HTTP_PARSER_ERRNO(&(kn->c_message->parser)))); 44 | return; 45 | } 46 | 47 | CParser* parser = kn->c_message; 48 | 49 | while(!(parser->messagelist.empty()) && parser->messagelist.front()->message_complete_cb_called){ 50 | Message* me = parser->messagelist.front(); 51 | parser->messagelist.pop_front(); 52 | me->fd = kn->fd; 53 | 54 | datapoll.inMsgQueue(me); 55 | } 56 | } -------------------------------------------------------------------------------- /net/cia_socket_response.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "cia_socket.h" 3 | 4 | 5 | 6 | 7 | void CSocket::cia_wait_responese_handler(Kevent_Node* kn){ 8 | // LOG_ACC(INFO, "开始写数据了----%s", kn->c_response->begin);s 9 | 10 | sendResponse(kn->c_response); 11 | 12 | return; 13 | } -------------------------------------------------------------------------------- /operation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_operation) 13 | # 指定生成目标 14 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library(${CIA_OUTPUT_NAME}_static STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /operation/cia_operation.cpp: -------------------------------------------------------------------------------- 1 | // #include 2 | // #include 3 | // #include "cia_operation.h" 4 | // #include "cia_comm.h" 5 | // // 要重写 6 | // // void porcRequest(Message* message){ 7 | // LOG_ACC(INFO,"线程threadid = %d 开始处理消息",std::this_thread::get_id()); 8 | // LOG_ACC(INFO,"------- 消息开始 ---------"); 9 | // // char buf[11] = "Received!"; 10 | // // int n = send(knode->fd, buf, strlen(buf), 0); 11 | // LOG_ACC(INFO, "URL: %s", (message->url).c_str()); 12 | // LOG_ACC(INFO, "Headers: "); 13 | // for(auto itre = (message->headers).begin(); itre != (message->headers).end(); itre++){ 14 | // LOG_ACC(INFO, "%s: %s", ((*itre)[0]).c_str(), ((*itre)[1]).c_str()); 15 | // } 16 | // LOG_ACC(INFO,"------- 消息结束 ---------"); 17 | // sleep(5); 18 | // LOG_ACC(INFO,"线程threadid = %d 结束处理消息",std::this_thread::get_id()); 19 | 20 | // delete message; 21 | 22 | // // char buf[1024] = "HTTP/1.1 200 OK\r\n"; 23 | 24 | // // "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" 25 | // // "Server: Apache\r\n" 26 | // // "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" 27 | // // "Content-Type: text/xml; charset=utf-8\r\n" 28 | // // "Connection: close\r\n" 29 | // // "\r\n"; 30 | // // "\n" 31 | // // "\n" 32 | // // " \n" 33 | // // " \n" 34 | // // " SOAP-ENV:Client\n" 35 | // // " Client Error\n" 36 | // // " \n" 37 | // // " \n" 38 | // // ""; 39 | // // int n = send(message->fd, buf, strlen(buf), 0); 40 | 41 | // // char buf1[] = "Content-Type: text/html\r\n"; 42 | // // n = send(message->fd, buf1, strlen(buf1), 0); 43 | 44 | // // char buf2[] = "\r\n"; 45 | 46 | // // n = send(message->fd, buf2, strlen(buf2), 0); 47 | 48 | // // char buf3[] = "Hello World\r\n"; 49 | // // n = send(message->fd, buf3, strlen(buf3), 0); 50 | 51 | // } 52 | 53 | -------------------------------------------------------------------------------- /operation/cia_operation.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_OPERATION_H__ 2 | #define __HEADERS_CIA_OPERATION_H__ 3 | // ------------ 业务相关的处理函数 -------------------------- 4 | #include "cia_log.h" 5 | #include "cia_socket.h" 6 | 7 | // 处理消息 8 | // void porcRequest(Message* knode); 9 | // void sendResponse(Response* msg); 10 | 11 | #endif //__HEADERS_CIA_OPERATION_H__ -------------------------------------------------------------------------------- /proc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_proc) 13 | # 指定生成目标 14 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library(${CIA_OUTPUT_NAME}_static STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /proc/cia_daemon.cpp: -------------------------------------------------------------------------------- 1 | 2 | // 创建守护进程步骤如下 3 | // (1)调用umask(0); 4 | // umask是个函数,用来限制(屏蔽)一些文件权限的。 5 | // (2)fork()一个子进程(脱离终端)出来,然后父进程退出( 把终端空出来,不让终端卡住);固定套路 6 | // fork()的目的是想成功调用setsid()来建立新会话,目的是 7 | // 子进程有单独的sid;而且子进程也成为了一个新进程组的组长进程;同时,子进程不关联任何终端了; 8 | // (3) 将输入、输出文件描述父重定向到/dev/null;用dup2 9 | #include "cia_setproctitle.h" 10 | #include "signal.h" 11 | #include "cia_log.h" 12 | int cia_daemon(){ 13 | pid_t pid; 14 | pid = fork(); 15 | for(;;){ 16 | if(pid == 0){ 17 | break; 18 | }else if(pid == -1){ 19 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:fork()出现错误"); 20 | return -1; 21 | }else{ 22 | return -2; 23 | } 24 | } 25 | 26 | umask(0); 27 | if(setsid() == -1){ 28 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:设置守护进程出现错误"); 29 | return -1; 30 | } 31 | int fd = open("/dev/null", O_RDWR); 32 | if(fd == -1){ 33 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:文件空洞/dev/null打开错误"); 34 | return -1; 35 | } 36 | if(dup2(fd, STDERR_FILENO) == -1){ 37 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:文件空洞/dev/null赋值STDERR_FILENO错误"); 38 | return -1; 39 | } 40 | if(dup2(fd, STDIN_FILENO) == -1){ 41 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:文件空洞/dev/null赋值STDIN_FILENO错误"); 42 | return -1; 43 | } 44 | if(dup2(fd, STDOUT_FILENO) == -1){ 45 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:文件空洞/dev/null赋值STDOUT_FILENO错误"); 46 | return -1; 47 | } 48 | if(close(fd) == -1){ 49 | LOG_ERR(WARN, "守护进程启动失败,结束程序运行:关闭文件空洞/dev/null错误"); 50 | return -1; 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /proc/cia_process_cycle.cpp: -------------------------------------------------------------------------------- 1 | // nginx中创建worker子进程 2 | //官方nginx ,一个master进程,创建了多个worker子进程; 3 | // master process ./nginx 4 | // worker process 5 | //(i)ngx_master_process_cycle() //创建子进程等一系列动作 6 | //(i) ngx_setproctitle() //设置进程标题 7 | //(i) ngx_start_worker_processes() //创建worker子进程 8 | //(i) for (i = 0; i < threadnums; i++) //master进程在走这个循环,来创建若干个子进程 9 | //(i) ngx_spawn_process(i,"worker process"); 10 | //(i) pid = fork(); //分叉,从原来的一个master进程(一个叉),分成两个叉(原有的master进程,以及一个新fork()出来的worker进程 11 | //(i) //只有子进程这个分叉才会执行ngx_worker_process_cycle() 12 | //(i) ngx_worker_process_cycle(inum,pprocname); //子进程分叉 13 | //(i) ngx_worker_process_init(); 14 | //(i) sigemptyset(&set); 15 | //(i) sigprocmask(SIG_SETMASK, &set, NULL); //允许接收所有信号 16 | //(i) ngx_setproctitle(pprocname); //重新为子进程设置标题为worker process 17 | //(i) for ( ;; ) {}. .... //子进程开始在这里不断的死循环 18 | //(i) sigemptyset(&set); 19 | //(i) for ( ;; ) {}. //父进程[master进程]会一直在这里循环 20 | #include "cia_setproctitle.h" 21 | #include "signal.h" 22 | #include "cia_log.h" 23 | #include "cia_kernal_func.h" 24 | #include "cia_global.h" 25 | // 清楚子进程的信号监听 26 | void clearsigmask(){ 27 | sigset_t set; 28 | sigemptyset(&set); 29 | if(sigprocmask(SIG_SETMASK, &set, NULL) == -1){ 30 | LOG_ERR(WARN, "重设子进程 pid=%d 的信号屏蔽字失败", getpid()); 31 | } 32 | } 33 | 34 | // 参数i表示是第几个worker进程 35 | void worker_process_init(int i){ 36 | 37 | process_type = i; // 通过process_type表示这个进程是父进程还是子进程 38 | 39 | LOG_ERR(WARN, "子进程 pid=%d 创建成功", getpid()); 40 | 41 | int thread_request_number = CConfig::getInstance()->GetIntDefault("Thread_number"); 42 | int thread_response_number = 1; 43 | if(threadpoll.init(thread_request_number, thread_response_number) == false){ 44 | exit(-2); 45 | } 46 | sleep(1); // 等等线程的创建,等1秒 47 | 48 | if(socket_ctl.epoll_init()== false){ // 设置epoll 49 | LOG_ERR(WARN, "子进程 pid=%d 设置epoll_init()失败,退出", getpid()); 50 | return; 51 | } 52 | // threadpoll.stopAll(); // 测试线程池关闭 53 | // 清空信号 54 | clearsigmask(); 55 | 56 | // 子进程初始化 57 | cia_setproctitle("lucia: worker process"); // 修改进程名称为lucia: worker process 58 | 59 | for(;;){ 60 | 61 | cia_process_events_and_timers(); 62 | // sleep(3); 63 | // 64 | } 65 | } 66 | 67 | void cia_create_worker_process(int workers){ 68 | pid_t ppid = getpid(); 69 | for(int i=0; iGetIntDefault("workers"); 93 | 94 | // 创建子进程 95 | cia_create_worker_process(worker_process_number); 96 | 97 | // 修改主进程名 98 | cia_setproctitle("lucia: master process"); // 修改进程名称为lucia: master process 99 | 100 | sigemptyset(&sig_new); 101 | 102 | for(;;){ 103 | // 阻塞在这里等待一个信号,等待一个信号,此时进程是挂起的,不会占用cpu时间,只有收到信号才会被唤醒 104 | // 原子操作 105 | // sigsuspend() 106 | //a)根据给定的参数设置新的mask 并 阻塞当前进程【因为是个空集,所以不阻塞任何信号】 107 | //b)此时,一旦收到信号,便恢复原先的信号屏蔽【我们原来的mask在上边设置的,阻塞了多达10个信号,从而保证我下边的执行流程不会再次被其他信号截断】 108 | //c)调用该信号对应的信号处理函数 109 | //d)信号处理函数返回后,sigsuspend返回,使程序流程继续往下走 110 | sigsuspend(&sig_new); 111 | LOG_ERR(INFO, "父进程执行一次信号。。。"); 112 | } 113 | } 114 | 115 | -------------------------------------------------------------------------------- /proc/cia_process_events_and_timers.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_kernal_func.h" 2 | #include "cia_global.h" 3 | void cia_process_events_and_timers(){ 4 | 5 | socket_ctl.cia_epoll_process_events(); 6 | } -------------------------------------------------------------------------------- /resource/git/Arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/resource/git/Arch.png -------------------------------------------------------------------------------- /resource/git/picture.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/resource/git/picture.pptx -------------------------------------------------------------------------------- /resource/git/thundering_herd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lsummer/LuciaArchitecture/6f1f0405be1b9e673f056e4729856a6fff388d1a/resource/git/thundering_herd.jpg -------------------------------------------------------------------------------- /resource/static/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 404 7 | 8 | 9 | 41 |
42 | 43 |
44 |

Hi,你浏览的页面不见了

45 |

点击下面图片,支持公益活动——举手之劳,投递你的爱心

46 |
47 |
48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /signal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_signal) 13 | # 指定生成目标 14 | #add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library(${CIA_OUTPUT_NAME}_static STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /signal/cia_signal.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_SIGNAL_H__ 2 | #define __HEADERS_CIA_SIGNAL_H__ 3 | 4 | #include "header.h" 5 | #include "cia_log.h" 6 | 7 | #define CIA_PROCESS_MASTER 0 8 | 9 | typedef struct{ 10 | int signo; // 信号编号 11 | std::string name; // 信号名字 12 | void (*handle)(int signo, siginfo_t* siginfo, void* handel); // 信号执行的操作 13 | }lucia_signal_t; 14 | 15 | void cia_process_sigchld(); 16 | 17 | void cia_singal_handel(int signo, siginfo_t *siginfo, void* ucontext); 18 | 19 | 20 | int cia_init_signals(); 21 | 22 | #endif -------------------------------------------------------------------------------- /signal/cia_singal.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "cia_signal.h" 3 | #include "cia_global.h" 4 | 5 | #include 6 | static std::vector signals = { 7 | // signo signame handler 8 | { SIGHUP, "SIGHUP", cia_singal_handel }, //终端断开信号,对于守护进程常用于reload重载配置文件通知--标识1 9 | { SIGINT, "SIGINT", cia_singal_handel }, //标识2 10 | { SIGTERM, "SIGTERM", cia_singal_handel }, //标识15 11 | { SIGCHLD, "SIGCHLD", cia_singal_handel }, //子进程退出时,父进程会收到这个信号--标识17 12 | { SIGQUIT, "SIGQUIT", cia_singal_handel }, //标识3 13 | { SIGIO, "SIGIO", cia_singal_handel }, //指示一个异步I/O事件【通用异步I/O信号】 14 | { SIGSYS, "SIGSYS, SIG_IGN", NULL }, //我们想忽略这个信号,SIGSYS表示收到了一个无效系统调用,如果我们不忽略,进程会被操作系统杀死,--标识31 15 | //所以我们把handler设置为NULL,代表 我要求忽略这个信号,请求操作系统不要执行缺省的该信号处理动作(杀掉我) 16 | //...日后根据需要再继续增加 17 | // { 0, NULL, NULL } //信号对应的数字至少是1,所以可以用0作为一个特殊标记 18 | }; 19 | 20 | 21 | 22 | int cia_init_signals(){ 23 | struct sigaction sa; 24 | 25 | for(auto sina = signals.begin(); sina != signals.end(); sina++){ 26 | // std::cout << sina->signo << sina->name << std::endl; 27 | memset(&sa, 0, sizeof(sa)); 28 | sigemptyset(&sa.sa_mask); 29 | if(sina->handle != NULL){ 30 | sa.sa_sigaction = sina->handle; 31 | sa.sa_flags = SA_SIGINFO; 32 | }else{ 33 | sa.sa_handler = SIG_IGN; 34 | } 35 | if(sigaction(sina->signo, &sa, NULL) == -1){ 36 | LOG_ERR(ERROR, "设置监听信号出现问题,返回"); 37 | return -1; 38 | }else{ 39 | LOG_ERR(INFO, "信号%s设置成功", &sina->name); 40 | } 41 | } 42 | return 0; 43 | } 44 | 45 | 46 | void cia_singal_handel(int signo, siginfo_t *siginfo, void* ucontext){ 47 | // 父进程和子进程对信号的处理不一样 48 | if(process_type == CIA_PROCESS_MASTER){ // 父进程 49 | switch (signo) 50 | { 51 | case SIGCHLD: 52 | // 当子进程结束的时候会向父进程发送SIGCHLD信号 53 | // 父进程需要捕获并调用waitpid()来避免子进程成为僵尸进程,其实子进程也需要处理,但是父进程可能需要处理一下 54 | /* code */ 55 | 56 | break; 57 | 58 | default: 59 | break; 60 | } 61 | }else{ // 子进程 62 | 63 | } 64 | 65 | 66 | switch (signo) 67 | { 68 | case SIGCHLD: 69 | /* code */ 70 | cia_process_sigchld(); 71 | break; 72 | 73 | default: 74 | break; 75 | } 76 | 77 | 78 | LOG_ERR(INFO, "接收到信号 %d, 信号已经处理", signo); 79 | // std::cout << "信号处理程序退出" << std::endl; 80 | } 81 | 82 | void cia_process_sigchld(){ 83 | int staloc; 84 | int err; 85 | int one = 0; // 作为标记,如果不为0表示被处理过 86 | pid_t pid; 87 | for(;;){ 88 | pid = waitpid(-1, &staloc, WNOHANG); 89 | if(pid == 0){ //表示子进程还没有结束 90 | return; 91 | }else if(pid == -1){ 92 | // 抄自nginx 93 | //这里处理代码抄自官方nginx,主要目的是打印一些日志。考虑到这些代码也许比较成熟,所以,就基本保持原样照抄吧; 94 | err = errno; 95 | if(err == EINTR){ //调用被某个信号中断 96 | continue; 97 | } 98 | 99 | if(err == ECHILD && one){ //没有子进程 100 | return; 101 | } 102 | 103 | if (err == ECHILD) //没有子进程 104 | { 105 | LOG_ERR(WARN, "waitpid() failed and err = ECHILD!"); 106 | return; 107 | } 108 | 109 | LOG_ERR(WARN, "waitpid() failed and err = %d!", err); 110 | return; 111 | } 112 | one = 1; // 表示信号处理过一次了 113 | /** 114 | * 子进程的结束状态返回后存于status,底下有几个宏可判别结束情况 115 | * WIFEXITED(status)如果子进程正常结束则为非0值。 116 | * WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。 117 | * WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真 118 | * WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。 119 | * WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。 120 | * WSTOPSIG(status)取得引发子进程暂停的信号代码. 121 | * */ 122 | 123 | if(WIFEXITED(staloc)){ 124 | LOG_ERR(INFO, "进程pid = %d 安全退出!", pid); 125 | }else{ 126 | LOG_ERR(WARN, "进程pid = %d 异常退出, 退出代码exitcode = %d", pid, WEXITSTATUS(staloc) ); 127 | if(WIFSIGNALED(staloc)){ 128 | LOG_ERR(WARN, "进程pid = %d 异常退出,使得该进程退出的信号代码sig_id = %d", pid, WTERMSIG(staloc)); 129 | } 130 | } 131 | return; 132 | } 133 | 134 | } -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | // mutex mutex1; 19 | // condition_variable cond; 20 | // unique_lock ulock(mutex1); 21 | // int label = 0; 22 | // void funcw(int& i){ 23 | // while(i<100){ 24 | // cond.wait(ulock, [](){return label == 0;}); 25 | // cout< binaryIndexedTree(const vector& vec){ 55 | // vector binarytree(vec.size()+1, 0); 56 | 57 | // for(int i=0; i& BIT){ 71 | // index+=1; 72 | // while(index < BIT.size()){ 73 | // BIT[index] += value; 74 | // index = index + (index & (-index)); 75 | // } 76 | // } 77 | 78 | // int prefixSum(int index, vector& BIT){ 79 | // index += 1; 80 | // int sum = 0; 81 | // while(index > 0){ 82 | // sum += BIT[index]; 83 | // index = index - (index & (-index)); 84 | // } 85 | // return sum; 86 | // } 87 | 88 | // int rangesum(int begin, int end, vector& BIT){ 89 | // return prefixSum(end) - prefixSum(begin-1); 90 | // } 91 | string str; 92 | void func(const char* x, int length){ 93 | str = string(x, x+length); 94 | 95 | // cout << "线程测试" << this_thread::get_id() << endl; 96 | } 97 | // struct th{ 98 | // thread* t; 99 | // th(thread* t):t(t){ 100 | 101 | // } 102 | // ~th(){} 103 | // }; 104 | // std::string GetGmtTime() 105 | // { 106 | // char szGmtTime[50]; 107 | 108 | // time_t rawTime; 109 | // struct tm* timeInfo; 110 | // char szTemp[30]={0}; 111 | // time(&rawTime); 112 | // timeInfo = gmtime(&rawTime); 113 | // strftime(szTemp,sizeof(szTemp),"%a, %d %b %Y %H:%M:%S GMT",timeInfo); 114 | // strcpy(szGmtTime, szTemp);//必须这样,避免内存释放,内容没有的问题。 115 | // // strncpy_s(szGmtTime, sizeof(szGmtTime), szTemp, strlen(szGmtTime)+1); 116 | // string time_str(szGmtTime, strlen(szGmtTime)); 117 | // return time_str; 118 | // } 119 | std::string GetGmtTime(const time_t* rawTime){ 120 | struct tm* timeInfo; 121 | char szTemp[30]={0}; 122 | timeInfo = gmtime(rawTime); 123 | strftime(szTemp,sizeof(szTemp),"%a, %d %b %Y %H:%M:%S GMT",timeInfo); 124 | 125 | string time_str(szTemp, strlen(szTemp)+1); 126 | return time_str; 127 | } 128 | int main(int argc, char* argv[]) 129 | { 130 | // thread* t1 = NULL; 131 | // th* ts = new th(t1); 132 | // cout << ts->t << endl; 133 | // t1 = new thread(func); 134 | // t1->join(); 135 | // ts->t = t1; 136 | // cout << ts->t << endl; 137 | // #ifdef __linux__ 138 | // cout<<"linxu环境" < x; 158 | // int* m = new int(1); 159 | // int* q = new int(2); 160 | // int* p = new int(3); 161 | // x.push_back(m); 162 | // x.push_back(q); 163 | // x.push_back(p); 164 | 165 | // x.pop_front(); 166 | // cout << (*m) < m; 222 | // string key, value; 223 | // key = "123"; 224 | // value = "123"; 225 | // m[key] = value; 226 | // for(auto x:m){ 227 | // cout << x.first << " : " << x.second << endl; 228 | // } 229 | string header = "Content-Disposition: form-data; name=\"arch\""; 230 | // string s = "/v1/test/callservice"; 231 | string name, filename; 232 | int name_begin = header.find("name=\"") + 6; 233 | int name_end = header.find("\"", name_begin); 234 | if(name_begin != std::string::npos){ 235 | if(name_end != std::string::npos){ 236 | name = header.substr(name_begin, name_end-name_begin); 237 | }else{ 238 | name = header.substr(name_begin); 239 | } 240 | }else{ 241 | name = ""; 242 | filename = ""; 243 | // return; 244 | } 245 | cout << name_begin <type = type; 41 | t = new std::thread(threads_func, std::ref(*item)); 42 | 43 | if(t == NULL){ 44 | LOG_ERR(ERROR, "创建线程失败"); 45 | return false; 46 | }else{ 47 | item->m_thread = t; 48 | cia_threads.push_back(item); 49 | } 50 | } 51 | 52 | auto itre = cia_threads.begin(); 53 | for(; itre != cia_threads.end(); itre++){ 54 | while((*itre)->isrunning == false){ 55 | usleep(100 * 1000); // 100ms 56 | } 57 | } 58 | LOG_ERR(INFO, "子进程 pid=%d 的 %d 线程池启动成功", getpid(), type); 59 | return true; 60 | } 61 | 62 | void CThreadPoll::stopAll(){ 63 | if(shutdown == true){ 64 | return; // 表示执行过了 65 | } 66 | shutdown = true; 67 | LOG_ERR(INFO, "子进程 pid=%d 线程池准备关闭", getpid()); 68 | 69 | cia_con_var.notify_all(); // 唤醒所有等待接受请求的线程 70 | cia_res_var.notify_all(); // 唤醒所有等待发送请求的线程 71 | 72 | // 屏障 join 73 | auto itre = cia_threads.begin(); 74 | for(; itre != cia_threads.end(); itre++){ 75 | if((*itre)->m_thread == NULL){ 76 | LOG_ERR(ERROR, "进程 pid=%d 的线程池的每项元素中的线程指针出现错误", getpid()); 77 | }else{ 78 | (*itre)->m_thread->join(); 79 | } 80 | } 81 | 82 | // 到这里一定所有线程都执行完了 83 | // 删除cia_threads 84 | itre = cia_threads.begin(); 85 | for(; itre != cia_threads.end(); itre++){ 86 | delete (*itre); 87 | (*itre) = NULL; 88 | } 89 | cia_threads.clear(); 90 | 91 | LOG_ERR(INFO, "子进程 pid=%d 线程池已全部关闭", getpid()); 92 | } 93 | 94 | void CThreadPoll::call_request(){ 95 | // 获得一个线程去执行 96 | cia_con_var.notify_one(); 97 | LOG_ERR(INFO, "进程pid=%d的线程运行数量为%d", getpid(),cia_running_thread.load()); 98 | if(cia_running_thread >= cia_thread_num * 0.9){ 99 | LOG_ERR(WARN, "进程线程测试目前已经快满了"); 100 | } 101 | } 102 | 103 | void CThreadPoll::call_response(){ 104 | // 获得一个线程去执行 105 | cia_res_var.notify_one(); 106 | } 107 | 108 | void CThreadPoll::threads_func(ThreadItem& item){ 109 | switch (item.type) 110 | { 111 | case CREQUEST: 112 | /* code */ 113 | threads_request_func(item); 114 | break; 115 | case CRESPONSE: 116 | /* code */ 117 | threads_response_func(item); 118 | break; 119 | default: 120 | break; 121 | } 122 | } 123 | 124 | 125 | void CThreadPoll::threads_request_func(ThreadItem& item){ 126 | // LOG_ERR(INFO, "线程池开始执行thread_pid = %d", std::this_thread::get_id()); 127 | for(;;){ 128 | while(shutdown == false && datapoll.empty()){ 129 | if(item.isrunning == false){ 130 | item.isrunning = true; 131 | } 132 | 133 | std::unique_lock ulock(cia_mutes_con); 134 | cia_con_var.wait(ulock); 135 | } 136 | //是否执行到这里 137 | // LOG_ERR(INFO, "线程向下执行到这里"); 138 | // 线程向下执行才是王道 139 | 140 | if(shutdown == true){ 141 | LOG_ERR(INFO, "线程结束运行"); 142 | break; // 表示结束运行 143 | } 144 | // 走到这里是真正开始执行 145 | item._this->cia_running_thread++; 146 | 147 | Message* request = datapoll.outMsgQueue(); // 成功读入数据,返回指针,否则返回NULL; 148 | if(request != NULL){ 149 | socket_ctl.porcRequest(request); 150 | } 151 | 152 | item._this->cia_running_thread--; 153 | } 154 | } 155 | 156 | void CThreadPoll::threads_response_func(ThreadItem& item){ 157 | // LOG_ERR(INFO, "线程池开始执行thread_pid = %d", std::this_thread::get_id()); 158 | for(;;){ 159 | while(shutdown == false && datapoll.resEmpty()){ 160 | if(item.isrunning == false){ 161 | item.isrunning = true; 162 | } 163 | 164 | std::unique_lock ulock(cia_mutex_response_con); 165 | cia_res_var.wait(ulock); 166 | } 167 | //是否执行到这里 168 | // LOG_ERR(INFO, "线程向下执行到这里"); 169 | // 线程向下执行才是王道 170 | 171 | if(shutdown == true){ 172 | LOG_ERR(INFO, "线程结束运行"); 173 | break; // 表示结束运行 174 | } 175 | // 走到这里是真正开始执行 176 | item._this->cia_running_response_thread++; 177 | 178 | Response* response = datapoll.outResQueue(); // 成功读入数据,返回指针,否则返回NULL; 179 | if(response != NULL){ 180 | // sendMessage(Response*); 181 | socket_ctl.sendResponse(response); 182 | } 183 | 184 | item._this->cia_running_response_thread--; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /threadpoll/cia_threadpoo.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_THREAD_POLL_H__ 2 | #define __HEADERS_CIA_THREAD_POLL_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum thread_type { CREQUEST, CRESPONSE, CNONE }; 11 | 12 | class CThreadPoll{ 13 | public: 14 | CThreadPoll(); 15 | ~CThreadPoll(); 16 | 17 | 18 | bool init(int request_num, int response_num); // 输入参数是处理request请求的线程池数量,和发送response线程池的数量(一般为1) 19 | bool create(int num, enum thread_type type); 20 | 21 | void stopAll(); // 结束所有 22 | void call_request(); // 召唤线程池干活 23 | void call_response(); // 召唤线程池干活 24 | private: 25 | 26 | // 线程池中的线程结构 27 | class ThreadItem{ 28 | public: 29 | bool isrunning; // 是否运行起来的标记 30 | std::thread* m_thread; // 线程指针 31 | CThreadPoll* _this; // 指向线程池的指针 32 | enum thread_type type; 33 | ThreadItem(std::thread* thre, CThreadPoll* cp):isrunning(false), m_thread(thre), _this(cp), type(CNONE){} 34 | ~ThreadItem(){} // 注意这里并没有释放线程指针,会统一在CthreadPoll的析构函数中或者释放线程池的成员函数中释放 35 | }; 36 | 37 | static bool shutdown; // 线程池结束标记 38 | std::vector cia_threads; // 有两种类别:处理request的线程池,处理response的线程池 39 | 40 | // 处理request的相关请求的线程池的相关数据,其实和reponse一样 41 | // std::mutex cia_mutex_message ; // 线程的互斥锁, message锁是为了锁住数据读取存入,con锁是为了条件变量 42 | static std::mutex cia_mutes_con; 43 | static std::condition_variable cia_con_var; // 线程池的条件变量 44 | std::atomic cia_running_thread; // 运行中的线程数目 45 | int cia_thread_num; // 线程池中的线程数量 46 | 47 | 48 | // 处理response的相关的区别,虽然使用信号量比较好,但是使用互斥量和条件变量完全可以是实现信号量,且更加安全 49 | static std::mutex cia_mutex_response_con; 50 | static std::condition_variable cia_res_var; // 线程池的条件变量 51 | std::atomic cia_running_response_thread; // 运行中的线程数目 52 | int cia_thread_res_num; // 线程池中处理response线程的数量,默认应该是1 53 | 54 | public: 55 | static void threads_func(ThreadItem& item); // 线程初始化函数 56 | static void threads_request_func(ThreadItem& item); 57 | static void threads_response_func(ThreadItem& item); 58 | }; 59 | 60 | #endif -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMake 最低版本号要求 2 | cmake_minimum_required (VERSION 3.8) 3 | 4 | # 查找当前目录下的所有源文件 5 | # 并将名称保存到 DIR_SRCS 变量 6 | aux_source_directory(. DIR_SRCS) 7 | 8 | # 换个地方保存生成的目标二进制文件 9 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 10 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 11 | 12 | set(CIA_OUTPUT_NAME cia_tools) 13 | # 指定生成目标 14 | # add_library(${CIA_OUTPUT_NAME} SHARED ${DIR_SRCS}) 15 | add_library(${CIA_OUTPUT_NAME}_static STATIC ${DIR_SRCS}) 16 | 17 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) 18 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1) 19 | set_target_properties(${CIA_OUTPUT_NAME}_static PROPERTIES OUTPUT_NAME ${CIA_OUTPUT_NAME}) 20 | #set_target_properties(${CIA_OUTPUT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1) 21 | -------------------------------------------------------------------------------- /tools/cia_conf.cpp: -------------------------------------------------------------------------------- 1 | #ifndef __TOOLS_CIA_CONF_CPP__ 2 | #define __TOOLS_CIA_CONF_CPP__ 3 | 4 | #include // https://zh.cppreference.com/w/cpp/regex/regex_match 5 | #include "header.h" 6 | #include "cia_conf.h" 7 | #include "cia_func.h" 8 | #include "cia_log.h" 9 | // 静态成员赋初值 10 | CConfig* CConfig::instance = nullptr; 11 | 12 | CConfig::CConfig(){} // 默认构造函数 13 | CConfig::CConfig(const CConfig& config){} // 拷贝构造函数 14 | CConfig::~CConfig(){ // 析构函数, 清楚掉每一个配置项的信息 15 | for(auto itre = static_map.begin(); itre != static_map.end(); itre++){ 16 | if((*itre) != NULL){ 17 | delete (*itre); 18 | (*itre) = NULL; 19 | } 20 | } 21 | static_map.clear(); 22 | static_map.shrink_to_fit(); 23 | conf_item_vector.clear(); 24 | } 25 | CConfig& CConfig::operator= (const CConfig& config){ // 赋值构造函数 26 | return *this; 27 | } 28 | 29 | CConfig* CConfig::getInstance(){ 30 | if( instance == nullptr ){ 31 | // 加锁 32 | if( instance == nullptr){ 33 | instance = new CConfig(); 34 | } 35 | // 解锁 36 | } 37 | return instance; 38 | } 39 | std::string CConfig::GetMime(const std::string& s){ 40 | if(mime.find(s) != mime.end()){ 41 | return mime[s]; 42 | }else{ 43 | return "text/plain"; 44 | } 45 | } 46 | 47 | bool CConfig::read_mime(){ 48 | std::string path = "./config/mime.types"; 49 | std::ifstream file(path); 50 | 51 | if(file){ 52 | std::string line; 53 | while(getline(file, line)){ 54 | if(line.length() > 0){ 55 | LRtrim(line); 56 | if(line.length() <= 0) continue; 57 | if(!read_mime_line(line)){ 58 | return false; 59 | } 60 | } 61 | } 62 | } 63 | return true; 64 | } 65 | 66 | bool CConfig::read_mime_line(std::string& str){ 67 | int begin = 0; 68 | std::vector vec; 69 | bool flag = true; 70 | for(int i=0; i 0){ 100 | LRtrim(line); // 去除前后空格 101 | 102 | // 判断是否是空格,判断是否是注释行 103 | if(line.length() <= 0) continue; 104 | if(line[0] == '#' || line[0] == '[' || line[0] == '\t' || line[0] == '\n' || line[0] == '{' || line[0] == '}') continue; 105 | 106 | EraseAnnoation(line); 107 | 108 | // 判断location, 静态资源映射 109 | if(line.length() > 8 && line.substr(0, 8) == "location"){ 110 | 111 | if(ParseLocation(line)){ 112 | continue; 113 | }else{ 114 | file.close(); 115 | return false; 116 | } 117 | } 118 | 119 | // 判断等号赋值 120 | std::string::size_type index = line.find_first_of("="); 121 | if(index != std::string::npos){ 122 | 123 | std::string iteamname = line.substr(0, int(index)); 124 | std::string iteamvalue = line.substr(int(index)+1); 125 | // EraseAnnoation(iteamname); 126 | // EraseAnnoation(iteamvalue); 127 | LRtrim(iteamname); 128 | LRtrim(iteamvalue); 129 | 130 | if(iteamname.length() > 0 && iteamvalue.length() > 0){ 131 | conf_item_vector[iteamname] = iteamvalue; 132 | } 133 | } 134 | } 135 | } 136 | 137 | file.close(); 138 | return true; 139 | } 140 | return false; 141 | } 142 | 143 | std::string CConfig::GetString(const std::string& s){ 144 | if(conf_item_vector.find(s) != conf_item_vector.end()){ 145 | return conf_item_vector[s]; 146 | } 147 | 148 | return ""; 149 | } 150 | 151 | int CConfig::GetIntDefault(const std::string& s){ 152 | std::string res = GetString(s); 153 | if(res.empty()){ 154 | return -1; 155 | } 156 | return std::stoi(res); 157 | } 158 | /** 159 | * # // 10. location 开头的表示一个静态资源映射地址 160 | # // 10.1 ~* 执行正则匹配,但不区分大小写 (四元组) location ~* pattern path 161 | # // 10.2 ~ 执行正则匹配,区分大小写 (四元组) location ~ pattern path 162 | # // 10.3 = 执行完全匹配 (四元组) location = pattern path 163 | # // 10.4 / 所有匹配 (三元组) location / path 164 | # // 10.5 ^~ 前缀匹配 (四元组)location ^~ pattern path 165 | # // 11. location 开头的表示一个RestFul API 166 | # // 11.1 ~* 执行正则匹配,但不区分大小写 (五元组) location ~* pattern API func 167 | # // 11.2 ~ 执行正则匹配,区分大小写 (五元组) location ~ pattern API func 168 | # // 11.3 = 执行完全匹配 (五元组) location = pattern API func 169 | # // 11.4 / 所有匹配 (四元组) location / API func 170 | # // 11.5 ^~ 前缀匹配 (五元组)location ^~ pattern API func 171 | # // 备注:为了更简洁方便地区分与静态资源服务器的区别,在func前需要加入关键字API,表示这是一个restful api请求 172 | * enum STATIC_MAP { RE, EQ, OT, PR, REU }; // RE表示不区分大小写的正则匹配「~*」,EQ表示相等「=」, OT表示其他「/」, PR表示「^~」, REU表示「~」 173 | 174 | * */ 175 | bool CConfig::ParseLocation(const std::string& str){ 176 | int begin = 0; 177 | std::vector vec; 178 | bool flag = true; 179 | for(int i=0; irule = RE; 197 | ctriple->pattern = vec[2]; 198 | ctriple->path = vec[3]; 199 | ctriple->request_type = 0; 200 | }else if(vec.size() == 5 && vec[3] == "API"){ 201 | ctriple->rule = RE; 202 | ctriple->pattern = vec[2]; 203 | ctriple->path = vec[4]; 204 | ctriple->request_type = 1; 205 | }else{ 206 | return false; 207 | } 208 | 209 | }else if(vec[1] == "="){ 210 | if(vec.size() == 4){ 211 | ctriple->rule = EQ; 212 | ctriple->pattern = vec[2]; 213 | ctriple->path = vec[3]; 214 | ctriple->request_type = 0; 215 | }else if(vec.size() == 5 && vec[3] == "API"){ 216 | ctriple->rule = EQ; 217 | ctriple->pattern = vec[2]; 218 | ctriple->path = vec[4]; 219 | ctriple->request_type = 1; 220 | }else{ 221 | // LOG_ACC(ERROR, "出现错误"); 222 | std::cout << "出现错误" << vec.size() << vec[3] << std::endl; 223 | return false; 224 | } 225 | 226 | }else if(vec[1] == "/"){ 227 | if(vec.size() == 3){ 228 | ctriple->rule = OT; 229 | // ctriple.pattern = vec[2]; 230 | ctriple->path = vec[2]; 231 | ctriple->request_type = 0; 232 | }else if(vec.size() == 4 && vec[2] == "API"){ 233 | ctriple->rule = OT; 234 | // ctriple->pattern = vec[2]; 235 | ctriple->path = vec[3]; 236 | ctriple->request_type = 1; 237 | }else{ 238 | return false; 239 | } 240 | }else if(vec[1] == "~"){ 241 | if(vec.size() == 4){ 242 | ctriple->pattern = vec[2]; 243 | ctriple->path = vec[3]; 244 | ctriple->rule = REU; 245 | ctriple->request_type = 0; 246 | }else if(vec.size() == 5 && vec[3] == "API"){ 247 | ctriple->rule = REU; 248 | ctriple->pattern = vec[2]; 249 | ctriple->path = vec[4]; 250 | ctriple->request_type = 1; 251 | }else{ 252 | return false; 253 | } 254 | }else if(vec[1] == "^~"){ 255 | if(vec.size() == 4){ 256 | ctriple->rule = PR; 257 | ctriple->pattern = vec[2]; 258 | ctriple->path = vec[3]; 259 | ctriple->request_type = 0; 260 | }else if(vec.size() == 5 && vec[3] == "API"){ 261 | ctriple->rule = PR; 262 | ctriple->pattern = vec[2]; 263 | ctriple->path = vec[4]; 264 | ctriple->request_type = 1; 265 | }else{ 266 | return false; 267 | } 268 | }else{ 269 | return false; 270 | } 271 | 272 | static_map.push_back(ctriple); 273 | 274 | return true; 275 | } 276 | 277 | int CConfig::RequestType(const std::string& s){ 278 | int i = 0; 279 | for(; i= static_map.size()){ 285 | return -1; 286 | } 287 | // LOG_ERR(DEBUG, "请求 %s的类型为:%d", s.c_str(),static_map[i]->request_type); 288 | return static_map[i]->request_type; 289 | 290 | } 291 | 292 | // 静态资源服务器 293 | std::string CConfig::GetPath(const std::string& s){ 294 | int i = 0; 295 | for(; irequest_type == 0){ // 既要匹配又要是静态资源服务器 297 | break; 298 | } 299 | } 300 | 301 | if(i >= static_map.size()){ 302 | return ""; // 表示失败了,没有匹配到任何静态资源地址 303 | } 304 | std::string val = static_map[i]->path + s; 305 | return val; 306 | // return static_map[i]->path + s; 307 | } 308 | 309 | bool CConfig::match(const std::string& s, const CTriple* triple){ 310 | 311 | std::regex txt_regex(triple->pattern, std::regex_constants::icase); 312 | std::regex txt2_regex(triple->pattern); 313 | 314 | switch (triple->rule) 315 | { 316 | case RE: 317 | /* code */ 318 | 319 | return std::regex_search(s, txt_regex); 320 | break; 321 | case REU: 322 | return std::regex_search(s, txt2_regex); 323 | break; 324 | case PR: 325 | return s.find(triple->pattern) == 0; 326 | break; 327 | 328 | case EQ: 329 | /* code */ 330 | if(s == triple->pattern) return true; 331 | return false; 332 | break; 333 | 334 | default: // OT 335 | return true; 336 | break; 337 | } 338 | } 339 | #endif 340 | -------------------------------------------------------------------------------- /tools/cia_conf.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_CONF_H__ 2 | #define __HEADERS_CIA_CONF_H__ 3 | 4 | /* ------------------------------------ 5 | // 功能: 加载配置文件的单例类 6 | // 描述: 配置文件解析说明 7 | // 1. 以 "#" 开头的行作为注释 8 | // 2. 以 "[" 开头的行作为注释 9 | // 3. 每一行前后空格会被忽略 10 | // 4. 空行会被忽略 11 | // 5. 参数设置格式为: 设置名=参数 12 | ------------------------------------ */ 13 | 14 | // 用到了正则匹配,参考网页:// https://zh.cppreference.com/w/cpp/regex/regex_match 15 | 16 | #include "header.h" 17 | 18 | enum STATIC_MAP { RE, EQ, OT, PR, REU }; // RE表示不区分大小写的正则匹配「~*」,EQ表示相等「=」, OT表示其他「/」, PR表示「^~」, REU表示「~」 19 | 20 | class CTriple{ 21 | public: 22 | enum STATIC_MAP rule; 23 | std::string pattern; 24 | std::string path; 25 | int request_type; // 0-静态资源请求,1-restful api请求 26 | }; 27 | 28 | class CConfig{ 29 | private: 30 | CConfig(); 31 | CConfig(const CConfig& config); 32 | CConfig& operator =(const CConfig& confi); 33 | bool ParseLocation(const std::string& str); 34 | public: 35 | ~CConfig(); 36 | 37 | static CConfig* getInstance(); 38 | 39 | bool load(const std::string& filename); // 加载配置文件,true表示加载成功, false表示加载失败 40 | 41 | bool read_mime(); 42 | bool read_mime_line(std::string& str); 43 | 44 | std::string GetString(const std::string& s); // 得到配置文件的参数 45 | int GetIntDefault(const std::string& s); // 得到配置文件的int参数 46 | 47 | // 得到静态资源的地址,首先根据static_map来得到静态资源的地址,然后拼接地址 48 | // 如果没有找到匹配地址,返回 "" 49 | std::string GetPath(const std::string& s); 50 | 51 | /** 52 | * 根据请求的URI判断 请求leix 53 | * 参数: 请求的URI 54 | * 返回值: -1 没有匹配的结果,0 静态资源请求, 1 RestFul API请求 55 | * */ 56 | int RequestType(const std::string& s); 57 | 58 | std::string GetMime(const std::string& s); 59 | 60 | void test_showAllitem(){ 61 | for(auto itre = conf_item_vector.begin(); itre != conf_item_vector.end(); itre++){ 62 | std::cout << itre->first << ": " << itre->second << std::endl; 63 | } 64 | } 65 | 66 | private: 67 | 68 | bool match(const std::string& s, const CTriple* triple); 69 | 70 | static CConfig* instance; 71 | std::map conf_item_vector; // 配置项 72 | std::map mime; // MIME_TYPE 73 | std::vector static_map; 74 | }; 75 | 76 | #endif -------------------------------------------------------------------------------- /tools/cia_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 字符串操作的一些函数 3 | 时间格式转换的一些函数 4 | */ 5 | 6 | #include "header.h" 7 | #include "cia_func.h" 8 | #include 9 | // 去掉左侧的空格 10 | void Ltrim(std::string& s){ 11 | s.erase(s.begin(), find_if(s.begin(), s.end(),[](const char a){return a!=' ';} ) ); 12 | } 13 | 14 | // 去掉右侧的空格 15 | void Rtrim(std::string& s){ 16 | auto itre = s.rbegin(); 17 | 18 | itre = find_if(s.rbegin(), s.rend(), [](const char a){return a != ' ';}); 19 | s.erase(itre.base(), s.end()); 20 | } 21 | 22 | // 去掉两侧的空格 23 | void LRtrim(std::string& s){ 24 | Ltrim(s); 25 | Rtrim(s); 26 | } 27 | // 去掉'#'及之后的所有值,'\#'表示'#' 28 | void EraseAnnoation(std::string& s){ 29 | int index = -1; 30 | for(int i=1; i 0){ 37 | s = s.substr(0, index); 38 | } 39 | } 40 | 41 | // ------------ 可变参数拼接操作 ------------------ 42 | int args_printf(std::string& result, const char* fmt, va_list args){ 43 | 44 | char* ch_res = new char[LOGS_SINGLE_MAX_CHARACTERS]; 45 | memset(ch_res, 0, LOGS_SINGLE_MAX_CHARACTERS); 46 | 47 | int size = vsprintf(ch_res, fmt, args); 48 | if(size > 0){ 49 | result = ch_res; 50 | } 51 | delete []ch_res; 52 | ch_res = NULL; 53 | return size; 54 | } 55 | 56 | // ------------ 将时间转换成GMT格式 ---------------- 57 | std::string GetGmtTime(const time_t* rawtime){ 58 | struct tm* timeInfo; 59 | char szTemp[30]={0}; 60 | timeInfo = gmtime(rawtime); 61 | strftime(szTemp,sizeof(szTemp),"%a, %d %b %Y %H:%M:%S GMT",timeInfo); 62 | 63 | std::string time_str(szTemp, strlen(szTemp)); 64 | return time_str; 65 | } -------------------------------------------------------------------------------- /tools/cia_func.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_CIA_FUNC_H__ 2 | #define __HEADERS_CIA_FUNC_H__ 3 | /* 4 | 对字符串操作的一些函数 5 | 对时间操作的一些函数 6 | */ 7 | // #include "header.h" 8 | 9 | #define LOGS_SINGLE_MAX_CHARACTERS 500 10 | 11 | // ----------- 字符串截取操作 ------------------- 12 | // 实现:../app/cia_func.cpp/ 13 | 14 | void Ltrim(std::string& s); // 去掉左侧的空格 15 | 16 | void Ltrim(std::string& s); // 去掉右侧的空格 17 | 18 | void LRtrim(std::string& s); // 去掉左右两侧的空格 19 | 20 | void EraseAnnoation(std::string& s); // 去掉‘#’代表的注释 21 | 22 | // ------------ 可变参数拼接操作 ------------------ 23 | int args_printf(std::string& result, const char* fmt, va_list args); 24 | 25 | // ------------ 时间转换成GMT格式 ----------------- 26 | // time_t rawTime; 27 | // time(&rawTime); 28 | std::string GetGmtTime(const time_t* rawtime); 29 | 30 | #endif -------------------------------------------------------------------------------- /tools/cia_setproctitle.cpp: -------------------------------------------------------------------------------- 1 | #include "cia_setproctitle.h" 2 | #include 3 | #include "cia_global.h" 4 | #include 5 | // 将环境变量搬家 6 | void cia_init_setprcotitle(){ 7 | g_environment = 0; 8 | 9 | for(int i=0; environ[i] != NULL; i++){ 10 | g_environment += (strlen(environ[i]) + 1); 11 | } 12 | // for(int i=0; environ[i] != NULL; i++){ 13 | // std::cout< havelenth){ 43 | std::cout << "名称太长,改名不成功!" << std::endl; 44 | return; 45 | } 46 | 47 | // for(int i=0; i