简化的nginx多进程模型demo
//version 1:以下代码仅演示nginx多进程模型
[test@vm c]$ cat mynginx.c
#include <stdio.h>
#include <string.h>
#include <unistd.h> char **os_argv;
char *os_argv_last;
init_setproctitle(void)
{
char *p;
size_t size;
int i; size = ; os_argv_last = os_argv[]; for (i = ; os_argv[i]; i++) {
if (os_argv_last == os_argv[i]) {
os_argv_last = os_argv[i] + strlen(os_argv[i]) + ;
}
}
os_argv_last += strlen(os_argv_last);
} void setproctitle(char *title)
{
char *p;
os_argv[] = NULL; p = strncpy((char *) os_argv[], (char *) title,
strlen(title));
p += strlen(title); if (os_argv_last - (char *) p > ) {
memset(p, ' ', os_argv_last - (char *) p);
} } void start_woker_processes()
{
setproctitle("mynginx:worker process");
for(;;)
{
sleep();
printf("worker pid=%d\n",getpid());
}
} void start_dispatcher_process()
{
setproctitle("mynginx:dispatcher process");
for(;;)
{
sleep();
printf("\tdispatcher pid=%d\n",getpid());
}
} void save_argv(int argc, char *const *argv)
{
os_argv = (char **) argv;
} int main(int argc, char **argv)
{
int fd;
int i;
pid_t pid;
save_argv(argc, argv);
init_setproctitle();
printf("father pid1=%d\n",getpid());
for (i = ; i <; i++)
{
pid = fork();
if (pid == )
{
start_woker_processes();
}
}
pid = fork();
if (pid == )
{
start_dispatcher_process();
}
printf("father pid2=%d\n",getpid());
while()
sleep();
return ;
}
make mynginx
./mynginx
ps -ef |grep mynginx 即可看到
test 20553 20463 0 23:54 pts/0 00:00:00 ./mynginx
test 20554 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20555 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20556 20553 0 23:54 pts/0 00:00:00 mynginx:worker process
test 20557 20553 0 23:54 pts/0 00:00:00 mynginx:dispatcher process
root 20574 20560 0 23:54 pts/2 00:00:00 grep mynginx
version 2:
改进:支持父进程重启被异常中断的子进程。
一个master,一个dispatcher,三个worker
[root@vm---- nginx-1.7.]# ps -ef | grep getslice
liubin : pts/ :: ./getslice
liubin : pts/ :: getslice:worker process
liubin : pts/ :: getslice:worker process
liubin : pts/ :: getslice:dispatcher process
liubin : pts/ :: getslice:worker process
[root@vm-10-154-252-59 nginx-1.7.10]# kill -9 745
[root@vm-10-154-252-59 nginx-1.7.10]# ps -ef | grep getslice
liubin 726 3469 0 20:00 pts/4 00:00:00 ./getslice
liubin 727 726 0 20:00 pts/4 00:00:00 getslice:worker process
liubin 728 726 0 20:00 pts/4 00:00:00 getslice:worker process
liubin 740 726 0 20:00 pts/4 00:00:00 getslice:dispatcher process
liubin 2714 726 0 20:30 pts/4 00:00:00 getslice:worker process
//可以看到,杀掉745后,马上又起来新的2714进程
下面是代码,可以直接编译
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> #define DefaultConfigFile "/opt/project/getslice/conf/getslice_lunbo.conf"
#define PID_FILENAME "/var/run/getslice_lunbo.pid"
#define VERSION "1.0.0" #define MAX_PROCESSES 128
#define PROCESS_NORESPAWN -1
#define PROCESS_JUST_SPAWN -2
#define PROCESS_RESPAWN -3
#define PROCESS_JUST_RESPAWN -4
#define PROCESS_DETACHED -5 const char *appname="getslice_lunbo";
char *ConfigFile = NULL; typedef void (*spawn_proc_pt) (void *data);
typedef struct {
pid_t pid;
int status;
//int channel[2]; spawn_proc_pt proc;
void *data;
char *name; unsigned respawn:;
unsigned just_spawn:;
unsigned detached:;
unsigned exiting:;
unsigned exited:;
} process_t;
process_t processes[MAX_PROCESSES];
int process_slot; /* getopt args*/
int opt_no_daemon = ;
int opt_debug_stderr = -;
int opt_parse_cfg_only = ;
int opt_send_signal = -; sig_atomic_t reap;
sig_atomic_t terminate;
sig_atomic_t quit;
int last_process;
int exiting; char **os_argv;
char *os_argv_last;
init_setproctitle(void)
{
char *p;
size_t size;
int i; size = ; os_argv_last = os_argv[]; for (i = ; os_argv[i]; i++) {
if (os_argv_last == os_argv[i]) {
os_argv_last = os_argv[i] + strlen(os_argv[i]) + ;
}
}
os_argv_last += strlen(os_argv_last);
} void setproctitle(char *title)
{
char *p;
os_argv[] = NULL; p = strncpy((char *) os_argv[], (char *) title,
strlen(title));
p += strlen(title); if (os_argv_last - (char *) p > ) {
memset(p, ' ', os_argv_last - (char *) p);
} } void worker_process_init(int worker)
{ } void worker_process_exit(void)
{ } void
worker_process_cycle(void *data)
{
int worker = (intptr_t) data; worker_process_init(worker); setproctitle("getslice:worker process"); for ( ;; ) {
if (exiting) {
fprintf(stderr, "exiting");
worker_process_exit();
}
sleep();
fprintf(stderr, "\tworker cycle pid: %d\n", getpid()); if (terminate) {
fprintf(stderr, "exiting");
worker_process_exit();
} if (quit) {
quit = ;
fprintf(stderr, "gracefully shutting down");
setproctitle("worker process is shutting down"); if (!exiting) {
exiting = ;
}
}
}
} void dispatcher_process_init(int worker)
{ } void dispatcher_process_exit()
{ } void
dispatcher_process_cycle(void *data)
{
int worker = (intptr_t) data; dispatcher_process_init(worker); setproctitle("getslice:dispatcher process"); for ( ;; ) {
if (exiting) {
fprintf(stderr, "exiting\n");
dispatcher_process_exit();
} sleep();
fprintf(stderr, "\tdispatcher cycle pid: %d\n", getpid()); if (terminate) {
fprintf(stderr, "exiting\n");
dispatcher_process_exit();
} if (quit) {
quit = ;
fprintf(stderr, "gracefully shutting down\n");
setproctitle("worker process is shutting down"); if (!exiting) {
exiting = ;
}
}
}
} void
start_worker_processes(int n, int type)
{
int i;
fprintf(stderr, "start worker processes\n"); for (i = ; i < n; i++) {
spawn_process(worker_process_cycle, (void *) (intptr_t) i, "worker process", type);
}
} void start_dispatcher_process(int type)
{
fprintf(stderr, "start dispatcher processes\n");
spawn_process(dispatcher_process_cycle, (void *) (intptr_t) , "dispatcher process", type);
} void save_argv(int argc, char *const *argv)
{
os_argv = (char **) argv;
} void
sig_child(int sig)
{
reap = ; int status;
int i;
pid_t pid; do {
pid = waitpid(-, &status, WNOHANG);
for (i = ; i < last_process; i++) {
if (processes[i].pid == pid) {
processes[i].status = status;
processes[i].exited = ;
//process = processes[i].name;
break;
}
}
} while (pid > );
signal(sig, sig_child);
} typedef void SIGHDLR(int sig);
void signal_set(int sig, SIGHDLR * func, int flags)
{
struct sigaction sa;
sa.sa_handler = func;
sa.sa_flags = flags;
sigemptyset(&sa.sa_mask);
if (sigaction(sig, &sa, NULL) < )
fprintf(stderr, "sigaction: sig=%d func=%p: %s\n", sig, func, strerror(errno));
} void init_signals(void)
{
signal_set(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
} static pid_t readPidFile(void)
{
FILE *pid_fp = NULL;
const char *f = PID_FILENAME;
pid_t pid = -;
int i; if (f == NULL) {
fprintf(stderr, "%s: error: no pid file name defined\n", appname);
exit();
} pid_fp = fopen(f, "r");
if (pid_fp != NULL) {
pid = ;
if (fscanf(pid_fp, "%d", &i) == )
pid = (pid_t) i;
fclose(pid_fp);
} else {
if (errno != ENOENT) {
fprintf(stderr, "%s: error: could not read pid file\n", appname);
fprintf(stderr, "\t%s: %s\n", f, strerror(errno));
exit();
}
}
return pid;
} int checkRunningPid(void)
{
pid_t pid;
pid = readPidFile();
if (pid < )
return ;
if (kill(pid, ) < )
return ;
fprintf(stderr, "getslice_master is already running! process id %ld\n", (long int) pid);
return ;
} void writePidFile(void)
{
FILE *fp;
const char *f = PID_FILENAME;
fp = fopen(f, "w+");
if (!fp) {
fprintf(stderr, "could not write pid file '%s': %s\n", f, strerror(errno));
return;
}
fprintf(fp, "%d\n", (int) getpid());
fclose(fp);
} void usage(void)
{
fprintf(stderr,
"Usage: %s [-?hvVN] [-d level] [-c config-file] [-k signal]\n"
" -h Print help message.\n"
" -v Show Version and exit.\n"
" -N No daemon mode.\n"
" -c file Use given config-file instead of\n"
" %s\n"
" -k reload|rotate|kill|parse\n"
" kill is fast shutdown\n"
" Parse configuration file, then send signal to \n"
" running copy (except -k parse) and exit.\n",
appname, DefaultConfigFile);
exit();
} static void show_version(void)
{
fprintf(stderr, "%s version: %s\n", appname,VERSION);
exit();
} void mainParseOptions(int argc, char *argv[])
{
extern char *optarg;
int c; while ((c = getopt(argc, argv, "hvNc:k:?")) != -) {
switch (c) {
case 'h':
usage();
break;
case 'v':
show_version();
break;
case 'N':
opt_no_daemon = ;
break;
case 'c':
ConfigFile = strdup(optarg);
break;
case 'k':
if ((int) strlen(optarg) < )
usage();
if (!strncmp(optarg, "reload", strlen(optarg)))
opt_send_signal = SIGHUP;
else if (!strncmp(optarg, "rotate", strlen(optarg)))
opt_send_signal = SIGUSR1;
else if (!strncmp(optarg, "shutdown", strlen(optarg)))
opt_send_signal = SIGTERM;
else if (!strncmp(optarg, "kill", strlen(optarg)))
opt_send_signal = SIGKILL;
else if (!strncmp(optarg, "parse", strlen(optarg)))
opt_parse_cfg_only = ; /* parse cfg file only */
else
usage();
break;
case '?':
default:
usage();
break;
}
}
} void enableCoredumps(void)
{
/* Set Linux DUMPABLE flag */
if (prctl(PR_SET_DUMPABLE, , , , ) != )
fprintf(stderr, "prctl: %s\n", strerror(errno)); /* Make sure coredumps are not limited */
struct rlimit rlim; if (getrlimit(RLIMIT_CORE, &rlim) == ) {
rlim.rlim_cur = rlim.rlim_max;
if (setrlimit(RLIMIT_CORE, &rlim) == ) {
fprintf(stderr, "Enable Core Dumps OK!\n");
return;
}
}
fprintf(stderr, "Enable Core Dump failed: %s\n",strerror(errno));
} int
reap_children(void)
{
int i, n;
int live; live = ;
for (i = ; i < last_process; i++) {
//child[0] 26718 e:0 t:0 d:0 r:1 j:0
fprintf(stderr,"child[%d] %d e:%d t:%d d:%d r:%d j:%d\n",
i,
processes[i].pid,
processes[i].exiting,
processes[i].exited,
processes[i].detached,
processes[i].respawn,
processes[i].just_spawn); if (processes[i].pid == -) {
continue;
} if (processes[i].exited) {
if (!processes[i].detached) {
for (n = ; n < last_process; n++) {
if (processes[n].exited
|| processes[n].pid == -)
{
continue;
} fprintf(stderr,"detached:%d\n", processes[n].pid);
}
} if (processes[i].respawn
&& !processes[i].exiting
&& !terminate
&& !quit)
{
if (spawn_process(processes[i].proc, processes[i].data, processes[i].name, i) == -)
{
fprintf(stderr, "could not respawn %s\n", processes[i].name);
continue;
} live = ; continue;
} if (i == last_process - ) {
last_process--; } else {
processes[i].pid = -;
} } else if (processes[i].exiting || !processes[i].detached) {
live = ;
}
} return live;
} pid_t
spawn_process(spawn_proc_pt proc, void *data, char *name, int respawn)
{
long on;
pid_t pid;
int s; if (respawn >= ) {
s = respawn; } else {
for (s = ; s < last_process; s++) {
if (processes[s].pid == -) {
break;
}
} if (s == MAX_PROCESSES) {
fprintf(stderr, "no more than %d processes can be spawned",
MAX_PROCESSES);
return -;
}
} process_slot = s; pid = fork(); switch (pid) { case -:
fprintf(stderr, "fork() failed while spawning \"%s\" :%s", name, errno);
return -; case :
pid = getpid();
proc(data);
break; default:
break;
} fprintf(stderr, "start %s %d\n", name, pid); processes[s].pid = pid;
processes[s].exited = ; if (respawn >= ) {
return pid;
} processes[s].proc = proc;
processes[s].data = data;
processes[s].name = name;
processes[s].exiting = ; switch (respawn) { case PROCESS_NORESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_JUST_SPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_RESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_JUST_RESPAWN:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break; case PROCESS_DETACHED:
processes[s].respawn = ;
processes[s].just_spawn = ;
processes[s].detached = ;
break;
} if (s == last_process) {
last_process++;
} return pid;
} int main(int argc, char **argv)
{
int fd;
int i;
pid_t pid;
sigset_t set; mainParseOptions(argc, argv);
if (- == opt_send_signal)
if (checkRunningPid())
exit(); enableCoredumps();
writePidFile();
save_argv(argc, argv);
init_setproctitle();
init_signals();
sigemptyset(&set); printf("father pid1=%d\n",getpid());
int worker_processes = ;
start_worker_processes(worker_processes, PROCESS_RESPAWN); start_dispatcher_process(PROCESS_RESPAWN);
printf("father pid2=%d\n",getpid()); int live = ;
for (;;) {
printf("father before suspend\n");
sigsuspend(&set);
printf("father after suspend\n");
if (reap) {
reap = ;
fprintf(stderr, "reap children\n");
live = reap_children();
}
}
return ;
}
简化的nginx多进程模型demo的更多相关文章
- nginx多进程模型之配置热加载---转
http://blog.csdn.net/brainkick/article/details/7176405 前言: 服务器程序通常都会通过相应的配置文件来控制服务器的工作.很多情况下,配置文件会经常 ...
- nginx和apache最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
nginx和apache的一些优缺点比较,摘自网络,加自己的一些整理. nginx相对于apache的优点: 1.轻量级,同样是web 服务,比apache 占用更少的内存及资源 2.抗并发,ngin ...
- nginx与apache 对比 apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
nginx与apache详细性能对比 http://m.blog.csdn.net/lengzijian/article/details/7699444 http://www.cnblogs.com/ ...
- Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- Nginx多进程高并发、低时延、高可靠机制在缓存代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- Nginx多进程高并发、低时延、高可靠机制缓存代理中的应用
1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...
- PHP 技能精进之 PHP-FPM 多进程模型
PHP-FPM 提供了更好的 PHP 进程管理方式,可以有效控制内存和进程.可以平滑重载PHP配置.那么当我们谈论 PHP-FPM 多进程模型的时候,作为 PHPer 的你了解多少呢? 首先,让我们一 ...
- Nginx 多进程连接请求/事件分发流程分析
Nginx使用多进程的方法进行任务处理,每个worker进程只有一个线程,单线程循环处理全部监听的事件.本文重点分析一下多进程间的负载均衡问题以及Nginx多进程事件处理流程,方便大家自己写程序的时候 ...
- nginx 多进程 + io多路复用 实现高并发
一.nginx 高并发原理 简单介绍:nginx 采用的是多进程(单线程) + io多路复用(epoll)模型 实现高并发 二.nginx 多进程 启动nginx 解析初始化配置文件后会 创建(for ...
随机推荐
- cf703B Mishka and trip
B. Mishka and trip time limit per test 1 second memory limit per test 256 megabytes input standard ...
- 用Processon在线绘制UML的尝试
地址https://www.processon.com/ ProcessOn是一个面向垂直专业领域的作图工具和社交网络,成立于2011年6月并于2012年启动.ProcessOn将全球的专家顾问.咨询 ...
- poj 1609 dp
题目链接:http://poj.org/problem?id=1609 #include <cstdio> #include <cstring> #include <io ...
- 阿里巴巴算法工程师四面(三轮技术+hr面)详细面经
阿里面试总结: 一遍一遍地刷阿里网站,今天发现“面试中”变成“待跟进offer”了,写个面经攒人品,希望offer通知邮件早点来吧. 我当时投简历时投了C/C++工程师,其实也没经过啥考虑,因为我一开 ...
- js提交前弹出提示框
<form target="_blank" name="f1" method="post" action="sub2.php ...
- JAVA中的继承和覆盖
java里面的继承是子类继承父类的一些方法和属性(除private属性和方法之外):对于父类的私有属性和方法子类是没有继承的.可是要想子类也能訪问到父类的私有属性,必须给私有属性以外界訪问的方法接口. ...
- Eclipse快捷键 10个最有用的快捷键(转)
Eclipse中10个最有用的快捷键组合 一个Eclipse骨灰级开发者总结了他认为最有用但又不太为人所知的快捷键组合.通过这些组合可以更加容易的浏览源代码,使得整体的开发效率和质量得到提升. ...
- ASP.NET过滤器、URL重写
过滤器可以对指定的URL访问进行拦截,并执行过滤器的方法,根据实际应用情况,在过滤器中修改请求的代码.判断会话信息,也可以做权限控制. 一:编写过滤器,实现URL重写并配置过滤 编写过滤器,就是编写一 ...
- Centos ssh 登陆乱码解决办法
1.vi /etc/sysconfig/i18n 将内容改为 LANG="zh_CN.GB18030"LANGUAGE="zh_CN.GB18030:zh_CN.GB23 ...
- Day12 - 堡垒机开发
Python之路,Day12 - 那就做个堡垒机吧 本节内容 项目实战:运维堡垒机开发 前景介绍 到目前为止,很多公司对堡垒机依然不太感冒,其实是没有充分认识到堡垒机在IT管理中的重要作用的,很多 ...