//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的更多相关文章

  1. nginx多进程模型之配置热加载---转

    http://blog.csdn.net/brainkick/article/details/7176405 前言: 服务器程序通常都会通过相应的配置文件来控制服务器的工作.很多情况下,配置文件会经常 ...

  2. nginx和apache最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程

    nginx和apache的一些优缺点比较,摘自网络,加自己的一些整理. nginx相对于apache的优点: 1.轻量级,同样是web 服务,比apache 占用更少的内存及资源 2.抗并发,ngin ...

  3. nginx与apache 对比 apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程

    nginx与apache详细性能对比 http://m.blog.csdn.net/lengzijian/article/details/7699444 http://www.cnblogs.com/ ...

  4. Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用

    1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...

  5. Nginx多进程高并发、低时延、高可靠机制在缓存代理中的应用

    1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...

  6. Nginx多进程高并发、低时延、高可靠机制缓存代理中的应用

    1. 开发背景 现有开源缓存代理中间件有twemproxy.codis等,其中twemproxy为单进程单线程模型,只支持memcache单机版和redis单机版,都不支持集群版功能. 由于twemp ...

  7. PHP 技能精进之 PHP-FPM 多进程模型

    PHP-FPM 提供了更好的 PHP 进程管理方式,可以有效控制内存和进程.可以平滑重载PHP配置.那么当我们谈论 PHP-FPM 多进程模型的时候,作为 PHPer 的你了解多少呢? 首先,让我们一 ...

  8. Nginx 多进程连接请求/事件分发流程分析

    Nginx使用多进程的方法进行任务处理,每个worker进程只有一个线程,单线程循环处理全部监听的事件.本文重点分析一下多进程间的负载均衡问题以及Nginx多进程事件处理流程,方便大家自己写程序的时候 ...

  9. nginx 多进程 + io多路复用 实现高并发

    一.nginx 高并发原理 简单介绍:nginx 采用的是多进程(单线程) + io多路复用(epoll)模型 实现高并发 二.nginx 多进程 启动nginx 解析初始化配置文件后会 创建(for ...

随机推荐

  1. 软工UML学习札记

    UML模型由:事物.关系和图组成 (1)类(class)── 类用带有类名.属性和操作的矩形框来表示. (2)主动类(active class)── 主动类的实例应具有一个或多个进程或线程,能够启动控 ...

  2. hdu 4579 博弈+区间dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597 #include <cstdio> #include <cstring> ...

  3. Java 内省 Introspector

    操纵类的属性,有两种方法 反射 内省 面向对象的编程中,对于用户提交过来的数据,要封装成一个javaBean,也就是对象 其中Bean的属性不是由字段来决定的,而是由get和Set方法来决定的 pub ...

  4. paip.输入法编程----删除双字词简拼

    paip.输入法编程----删除双字词简拼 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.net/at ...

  5. HDU-1053-Entropy(Huffman编码)

    Problem Description An entropy encoder is a data encoding method that achieves lossless data compres ...

  6. mac下使用brew安装svn javahl的问题

    eclipse老提示javahl太久必须得1.8以上,以前不知道什么时候在/usr/bin装过1.7的svn. 1. 删除1.7的svn sudo rm /usr/bin/svn 2.使用brew安装 ...

  7. 关于 yii 验证码显示, 但点击不能刷新的处理

    先说说 render 与 renderPartial, 各位看官, 先别走, 我没跑题, 这个问题如果需要解决, 关键就在 render 与 renderPartial 的区别. renderPart ...

  8. Linux开发工具之Makefile(上)

    二.makefile(上) 01.make工具   利用make工具可以自动完成编译工作.这些工作包括:如果修改了某几 个源文件,则只重装新编译这几个源文件:如果某个头文件被修改了,则 重新编译所有包 ...

  9. NYOJ2括号配对问题

    括号配对是最基本的栈的问题,它是栈入门的经典题目,思路是,如果是左括号直接进栈,如果是右括号,这时就要比较栈顶的元素与他是否匹配,如果匹配则出栈,否则进栈,下面是代码的实现: #include < ...

  10. 本文实例汇总了C#中@的用法,对C#程序设计来说有不错的借鉴价值。

    具体如下: 一 字符串中的用法 1.学过C#的人都知道C# 中字符串常量可以以@ 开头声名,这样的优点是转义序列“不”被处理,按“原样”输出,即我们不需要对转义字符加上 \ (反斜扛),就可以轻松co ...