//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. mac下的改装人生——制作mac os 启动盘

    我即将开始对我的mac进行彻底的改造,现在还需要的是一个mac的启动盘或者启动光盘.由于没钱买mac的安装光盘或者安装盘,只能网上下了一个镜像自己做启动盘~ 需要:装有Mac Os的电脑,至少8g的u ...

  2. Servlet的一些细节(2)

    1. Servlet的创建时间 Servlet是不能单独运行,调用它的叫做Servlet引擎,或者叫做web服务器 针对客户端的多长Servlet请求,通常情况下,服务器只会创建一个Servlet实例 ...

  3. VC++ 动态检测串口的热插拔(一)通过注册表实现

    在上一篇文章中讲述了如何通过循环遍历的方法获取可用串口,可是这样的方法过于暴力,难免会想有没有其他的办法那,嘿嘿,那是肯定会有的,不管什么问题,解决问题的方法永远都不止一种.下面讲述如何通过注册表来获 ...

  4. 《Linux命令行与shell脚本编程大全》 第二十七章 学习笔记

    第二十七章:shell脚本编程进阶 监测系统统计数据 系统快照报告 1.运行时间 uptime命令会提供以下基本信息: 当前时间 系统运行的天数,小时数,分钟数 当前登录到系统的用户数 1分钟,5分钟 ...

  5. mybatis 多参数处理

    接口交互比较多, 所以 入参比较多,  有五个参数,是排序 参数, 跟这个五个参数排序,本来想写个对象的, 怕麻烦, 就把 五个参数 变成一个参数, 升序 1 ,降序2 ,比如  11221 ,第三第 ...

  6. [PWA] 10. Trigger a version update

    When the refersh button is clicked, we need to tell the waiting service worker to replace the curren ...

  7. 安全的PHP代码编写准则(转)

    绝不要信任外部数据或输入 关于 Web 应用程序安全性,必须认识到的第一件事是不应该信任外部数据.外部数据(outside data) 包括不是由程序员在 PHP 代码中直接输入的任何数据.在采取措施 ...

  8. 在VisualStudio 2012中通过SmallSharp压缩js及修改web.config

    在项目中加入一个targets文件,取名my.build.targets 在targets文件中加入内容: <?xml version="1.0" encoding=&quo ...

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

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

  10. Centos清理内存 内存回收释放及内存使用查看的相关命令

    在清理前内存使用情况 free -m 用以下命令清理内存 echo 1 > /proc/sys/vm/drop_caches 清理后内存使用情况再用以下命令看看. free –m 多出很多内存了 ...