简化的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 ...
随机推荐
- rpm常用操作
1.查询.检查软件包 rpm {-q|--query} [select-options] [query-options] rpm {-V|--verify} [select-options] [ver ...
- bzoj2049: [Sdoi2008]Cave 洞穴勘测
lct入门题? 得换根了吧TAT 这大概不是很成熟的版本.. #include<iostream> #include<cstring> #include<cstdlib& ...
- url传递中文的解决方案
本文转载:http://www.cnblogs.com/ghd258/archive/2005/10/23/260241.html url传递中文的解决方案 1.设置web.config文件. < ...
- LinearLayout增加divider分割线
在android3.0及后面的版本在LinearLayout里增加了个分割线 1 2 android:divider="@drawable/shape"<!--分割线图片-- ...
- Android源代码分析之Framework的MediaPlayer
在Android中MediaPlayer用来播放音频和视频文件,在这里分析下在Framework层中MediaPlayer是怎样调用的.MediaPlayer的代码位于:./frameworks/ba ...
- navicat导入mysql数据库sql时报错或数据不完全问题
错误详情:[Err] [Imp] 2006 - MySQL server has gone away 或无提示错误,但是导入数据明显缺少字段和数据 找到服务器上的MYSQL安装目录下的my.ini文件 ...
- Android(java)学习笔记222:开发一个多界面的应用程序之不同界面间互相传递数据(短信助手案例的优化:请求码和结果码)
1.开启界面获取返回值 (1)采用一种特殊的方式开启Activity: startActivityForResult(intent , 0): (2)在被开启的Activi ...
- ie下面兼容性问题的一些总结
最后一次搞ie兼容性问题,以后都可以不管了0.0 1.浮动兼容性 1.1IE6下的双边距BUG 在IE6下,块元素有浮动和横向margin的时候,最边上元素的横向margin值会被放大成两倍 解决办法 ...
- java编程思想-注解思维导图
- tomcat - 部署Web应用
概述 以前,安装李刚的JavaEE里面说的方法部署应用的时候,无意中成功,但是后来每次要录视频的时候,又报错,思来想去,tomcat都重启了好多次了,配置文件也试过很多次了,还是不行.无意中发现了问题 ...