给Nginx添加FastCGI处理程序,不使用spawn-fcgi工具并实现守护功能

本文介绍了一种使FastCGI程序能在Nginx中自动重启的方法,通过监听子进程状态来实现故障自动恢复,确保服务稳定运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前看到网友给Nginx添加FastCGI(C语言)程序时,基本上都使用了spawn-fcgi工具,我开始也是按照这种模式,但是发现spawn-fcgi不能监视子进程,原因是它在fork后,将子进程替换为了我们的fcgi程序,父进程则退出了。但是在高并发及长时间运行后,子进程难免会挂掉,这时就不能快速自动重启fcgi程序,影响用户正常访问。
偶然在翻看fcgi库源码时,发现fcgi库自身支持绑定并监听套接字。因此自己试了下,确实可以使用。


环境:
1. CentOS 6.3 32bit
2. Nginx 1.7.5

3. Fcgi-2.4.1


安装过程就不说了,看README和INSTALL文件,或者configure –h


下面简单说下代码

首先处理2个信号SIGCHLD和SIGTERM
signal(SIGCHLD, sig_handler);
signal(SIGTERM, sig_handler);


然后创建子进程处理逻辑,父进程则监听子进程结束的信号
pid = fork();
switch(pid)
{
case 0: 
run_child();
break;
case -1:
syslog(LOG_INFO, "fork error"); 
return -1;
default:
wait(NULL);
break;
}


信号处理函数
void sig_handler(int sig_no)
{
switch(sig_no)
{
// 如果子进程结束则马上重启
case SIGCHLD:
pid = fork();
switch(pid)
{
case 0:
run_child();
break;
case -1:
exit(-1);
default:
wait(NULL);
break;
}
break;


// 如果父进程收到SIGTERM信号,则结束父子进程
case SIGTERM:
if(pid > 0)
kill(pid, SIGTERM);
exit(0);
default:
break;
}
}


对于监听套接字,主要是2个函数
socketId = FCGX_OpenSocket("/var/run/fcgi.sock", 1024) // unix domain
socketId = FCGX_OpenSocket(":9000", 1024) // tcp/ip


FCGX_InitRequest(&request, socketId, 0)


其实还是比较简单,下面是完整代码

#include "fcgi_config.h"

#include 
#include 
#include 
#include     
#include   
#include 
#include 

#include "fcgiapp.h" 

#define THREAD_COUNT 	20
#define UNIX_SOCK		"/var/run/fcgi.sock"


static int counts[THREAD_COUNT];
int socketId;
pid_t pid;

void run_child();

static void *doit(void *a)
{
	int rc, i, thread_id = (int)a;
	pid_t pid = getpid();
	FCGX_Request request;
	char *server_name;

	if(FCGX_InitRequest(&request, socketId, 0) != 0) 
	{ 	
		return NULL; 
	}

	for (;;)
	{
		static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
		static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER;

		/* Some platforms require accept() serialization, some don't.. */
		pthread_mutex_lock(&accept_mutex);
		rc = FCGX_Accept_r(&request);
		pthread_mutex_unlock(&accept_mutex);

		if (rc < 0)
			break;

		server_name = FCGX_GetParam("SERVER_NAME", request.envp);	

		FCGX_FPrintF(request.out,
			"Content-type: text/html\r\n"
			"\r\n"
			"FastCGI Hello! (multi-threaded C, fcgiapp library)"
			"

FastCGI Hello! (multi-threaded C, fcgiapp library)

" "Thread %d, Process %ld

" "Request counts for %d threads running on host %s

", thread_id, pid, THREAD_COUNT, server_name ? server_name : "?"); pthread_mutex_lock(&counts_mutex); ++counts[thread_id]; for (i = 0; i < THREAD_COUNT; i++) FCGX_FPrintF(request.out, "%5d " , counts[i]); pthread_mutex_unlock(&counts_mutex); FCGX_Finish_r(&request); } return NULL; } void sig_handler(int sig_no) { switch(sig_no) { case SIGCHLD: syslog(LOG_INFO, "child exit"); pid = fork(); switch(pid) { case 0: run_child(); break; case -1: syslog(LOG_INFO, "fork error"); exit(-1); default: wait(NULL); break; } break; case SIGTERM: if(pid > 0) { kill(pid, SIGTERM); } syslog(LOG_INFO, "program terminating..\n"); closelog(); exit(0); default: break; } } void run_child() { int i; pthread_t id[THREAD_COUNT]; syslog(LOG_INFO, "child staring..\n"); FCGX_Init(); umask(0); //if( (socketId = FCGX_OpenSocket(UNIX_SOCK, 1024)) < 0) if( (socketId = FCGX_OpenSocket(":9000", 1024)) < 0) { syslog(LOG_INFO, "FCGX_OpenSocket failed\n"); exit(1); } for (i = 1; i < THREAD_COUNT; i++) { pthread_create(&id[i], NULL, doit, (void*)i); } doit(0); } int main(void) { daemon(1, 1); signal(SIGCHLD, sig_handler); signal(SIGTERM, sig_handler); openlog("fcgi_threads", LOG_PID, LOG_USER); syslog(LOG_INFO, "program starting.."); pid = fork(); switch(pid) { case 0: run_child(); break; case -1: syslog(LOG_INFO, "fork error"); return -1; default: wait(NULL); break; } return 0; }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值