windows下的Nginx和php搭配 php-cgi.exe自动关闭退出解决方法
2017-03-04 10:26
423 查看
http://down.chinaz.com/server/201111/1334_1.htm
php-cgi.exe在windows+nginx平台下经常自动退出,网上搜到的大部分解决方法都是类似上面的批处理(代码如下)文件临时解决一下,但如果用户在网站登录的话,用户就会突然挂掉。
一个批处理文件
@echo off
:main
set jinchengshuliang=0
set jinchengshuliangxiaxian=2
for /f %%i in ('tasklist /nh^|findstr /i /s /c:"php-cgi.exe"') do set /a jinchengshuliang+=1
if %jinchengshuliang% lss %jinchengshuliangxiaxian% (
goto youwenti
) else (
goto meiwenti
)
:youwenti
echo 进程丢失,现在添加5个进程
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
ping 127.1 -n 8
goto main
:meiwenti
echo 正常运行中!
ping 127.1 -n 8
goto main最好的解决办法是用windows下的php-cgi进程管理器,该进程管理器需要用到pthreadGC2.dll。源码和编译文件在本文结尾提供下载。经测试,支持Win32和Linux-x86平台。对于用php的人,有了这个东西来维护一定数量的进程,就能制服经常崩溃退出的php-cgi啦!
以下是xxfpm进程管理器的操作参数:
第一个写得比较标准的终端应用程序,我是看了cygwin的里的一些源代码,然后学会了如何使用getopt,算是写得比较标准的,但是代码也不短。
使用例子:
有人问,如何给程序加入参数?这个不难,使用双引号即可,路径要用"/"而不用"\"。例如要指定php.ini的路径,可以用下面例子:
维护进程原理:
Windows上使用CreateProcess创建进程,使用Wait For Single Object等待进程结束;Linux上使用fork和execl创建进程,使用waitpid等待进程结束。Linux的版本多了在创建子进程的时候可以设置进程限制,能够以受限用户方式来运行。
当进程管理器被关闭的时候,它所创建的所有子进程也必须被关闭。Windows上使用JobObject这个东西来把子进程与管理器的进程产生关联,感谢iceboy提供的资料!Linux上通过捕捉关闭信号,然后给所有子进程发送SIGTERM来结束子进程。详见源代码:
php-cgi.exe在windows+nginx平台下经常自动退出,网上搜到的大部分解决方法都是类似上面的批处理(代码如下)文件临时解决一下,但如果用户在网站登录的话,用户就会突然挂掉。
一个批处理文件
@echo off
:main
set jinchengshuliang=0
set jinchengshuliangxiaxian=2
for /f %%i in ('tasklist /nh^|findstr /i /s /c:"php-cgi.exe"') do set /a jinchengshuliang+=1
if %jinchengshuliang% lss %jinchengshuliangxiaxian% (
goto youwenti
) else (
goto meiwenti
)
:youwenti
echo 进程丢失,现在添加5个进程
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
RunHiddenConsole.exe php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.ini
ping 127.1 -n 8
goto main
:meiwenti
echo 正常运行中!
ping 127.1 -n 8
goto main最好的解决办法是用windows下的php-cgi进程管理器,该进程管理器需要用到pthreadGC2.dll。源码和编译文件在本文结尾提供下载。经测试,支持Win32和Linux-x86平台。对于用php的人,有了这个东西来维护一定数量的进程,就能制服经常崩溃退出的php-cgi啦!
以下是xxfpm进程管理器的操作参数:
Usage: xxfpm path [-n number] [-i ip] [-p port] Manage FastCGI processes. -n, --number number of processes to keep -i, --ip ip address to bind -p, --port port to bind, default is 8000 -u, --user start processes using specified linux user -g, --group start processes using specified linux group -r, --root change root direcotry for the processes -h, --help output usage information and exit -v, --version output version information and exit
第一个写得比较标准的终端应用程序,我是看了cygwin的里的一些源代码,然后学会了如何使用getopt,算是写得比较标准的,但是代码也不短。
使用例子:
xxfpm z:/php5/php-cgi.exe -n 5 -p 8080
有人问,如何给程序加入参数?这个不难,使用双引号即可,路径要用"/"而不用"\"。例如要指定php.ini的路径,可以用下面例子:
xxfpm "z:/php5/php-cgi.exe -c z:/php5/php.ini" -n 5 -i 127.0.0.1 -p 8080
维护进程原理:
Windows上使用CreateProcess创建进程,使用Wait For Single Object等待进程结束;Linux上使用fork和execl创建进程,使用waitpid等待进程结束。Linux的版本多了在创建子进程的时候可以设置进程限制,能够以受限用户方式来运行。
当进程管理器被关闭的时候,它所创建的所有子进程也必须被关闭。Windows上使用JobObject这个东西来把子进程与管理器的进程产生关联,感谢iceboy提供的资料!Linux上通过捕捉关闭信号,然后给所有子进程发送SIGTERM来结束子进程。详见源代码:
#ifdef __WIN32__ #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0500 #endif //_WIN32_WINNT #include <windows.h> #include <winsock.h> #include <wininet.h> #define SHUT_RDWR SD_BOTH #ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE (0x2000) #endif HANDLE FcpJobObject; #else #include <sys/socket.h> #include <sys/wait.h> #include <fcntl.h> #include <arpa/inet.h> #include <grp.h> #include <pwd.h> #include <unistd.h> #define closesocket close #endif //__WIN32__ #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <string.h> #include <pthread.h> #include <errno.h> #define MAX_PROCESSES 1024 static const char version[] = "$Revision: 0.01 $"; static char* prog_name; int number = 1; int port = 8000; char *ip = "127.0.0.1"; char *user = ""; char *root = ""; char *path = ""; char *group = ""; int listen_fd; struct sockaddr_in listen_addr; int process_fp[MAX_PROCESSES]; int process_idx = 0; pthread_t threads[MAX_PROCESSES]; static struct option longopts[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {"number", required_argument, NULL, 'n'}, {"ip", required_argument, NULL, 'i'}, {"port", required_argument, NULL, 'p'}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"root", required_argument, NULL, 'r'}, {NULL, 0, NULL, 0} }; static char opts[] = "hvnipugr"; static void usage(FILE* where) { fprintf(where, "" "Usage: %s path [-n number] [-i ip] [-p port]\n" "Manage FastCGI processes.\n" "\n" " -n, --number number of processes to keep\n" " -i, --ip ip address to bind\n" " -p, --port port to bind, default is 8000\n" " -u, --user start processes using specified linux user\n" " -g, --group start processes using specified linux group\n" " -r, --root change root direcotry for the processes\n" " -h, --help output usage information and exit\n" " -v, --version output version information and exit\n" "", prog_name); exit(where == stderr ? 1:0); } static void print_version() { printf("%s %s\n\ FastCGI Process Manager\n\ Copyright 2010 Xiaoxia.org\n\ Compiled on %s\n\ ", prog_name, version, __DATE__); exit(0); } static int try_to_bind() { listen_addr.sin_family = PF_INET; listen_addr.sin_addr.s_addr = inet_addr( ip ); listen_addr.sin_port = htons( port ); listen_fd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == bind(listen_fd, (struct sockaddr*)&listen_addr, sizeof(struct sockaddr_in)) ) { fprintf(stderr, "failed to bind %s:%d\n", ip, port ); return -1; } listen(listen_fd, MAX_PROCESSES); return 0; } static void* spawn_process(void* arg) { int idx = process_idx ++, ret; while(1){ #ifdef __WIN32__ STARTUPINFO si={0}; PROCESS_INFORMATION pi={0}; ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = (HANDLE)listen_fd; si.hStdOutput = INVALID_HANDLE_VALUE; si.hStdError = INVALID_HANDLE_VALUE; if(0 == (ret=CreateProcess(NULL, path, NULL,NULL, TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, NULL,NULL, &si,&pi)) ){ fprintf(stderr, "failed to create process %s, ret=%d\n", path, ret); return NULL; } /* Use Job Control System */ if(!AssignProcessToJobObject(FcpJobObject, pi.hProcess)){ TerminateProcess(pi.hProcess, 1); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return NULL; } if(!ResumeThread(pi.hThread)){ TerminateProcess(pi.hProcess, 1); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return NULL; } process_fp[idx] = (int)pi.hProcess; WaitForSingleObject(pi.hProcess, INFINITE); process_fp[idx] = 0; CloseHandle(pi.hThread); #else ret = fork(); switch(ret){ case 0:{ //child /* change uid from root to other user */ if(getuid()==0){ struct group *grp = NULL; struct passwd *pwd = NULL; if (*user) { if (NULL == (pwd = getpwnam(user))) { fprintf(stderr, "[fcgi] %s %s\n", "can't find username", user); exit(-1); } if (pwd->pw_uid == 0) { fprintf(stderr, "[fcgi] %s\n", "what? dest uid == 0?" ); exit(-1); } } if (*group) { if (NULL == (grp = getgrnam(group))) { fprintf(stderr, "[fcgi] %s %s\n", "can't find groupname", group); exit(1); } if (grp->gr_gid == 0) { fprintf(stderr, "[fcgi] %s\n", "what? dest gid == 0?" ); exit(1); } /* do the change before we do the chroot() */ setgid(grp->gr_gid); setgroups(0, NULL); if (user) { initgroups(user, grp->gr_gid); } } if (*root) { if (-1 == chroot(root)) { fprintf(stderr, "[fcgi] %s %s\n", "can't change root", root); exit(1); } if (-1 == chdir("/")) { fprintf(stderr, "[fcgi] %s %s\n", "can't change dir to", root); exit(1); } } /* drop root privs */ if (*user) { setuid(pwd->pw_uid); } } int max_fd = 0, i=0; // Set stdin to listen_fd close(STDIN_FILENO); dup2(listen_fd, STDIN_FILENO); close(listen_fd); // Set stdout and stderr to dummy fd max_fd = open("/dev/null", O_RDWR); close(STDERR_FILENO); dup2(max_fd, STDERR_FILENO); close(max_fd); max_fd = open("/dev/null", O_RDWR); close(STDOUT_FILENO); dup2(max_fd, STDOUT_FILENO); close(max_fd); // close other handles for(i=3; i<max_fd; i++) close(i); char *b = malloc(strlen("exec ") + strlen(path) + 1); strcpy(b, "exec "); strcat(b, path); /* exec the cgi */ execl("/bin/sh", "sh", "-c", b, (char *)NULL); exit(errno); break; } case -1: fprintf(stderr, "[fcgi] fork failed\n"); return NULL; default:{ struct timeval tv = { 0, 100 * 1000 }; int status; select(0, NULL, NULL, NULL, &tv); switch(waitpid(ret, &status, WNOHANG)){ case 0: printf("[fcg] spawned process %s: %d\n", path, ret); break; case -1: fprintf(stderr, "[fcgi] waitpid failed\n"); return NULL; default: if (WIFEXITED(status)) { fprintf(stderr, "[fcgi] child exited with: %d\n", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { fprintf(stderr, "[fcgi] child signaled: %d\n", WTERMSIG(status)); } else { fprintf(stderr, "[fcgi] child died somehow: %d\n", status); } return NULL; } //wait for child process to exit process_fp[idx] = ret; waitpid(ret, &status, 0); process_fp[idx] = 0; } } #endif } } static int start_processes() { int i; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 64*1024); //64KB for(i=0; i<number; i++){ if( pthread_create( &threads, &attr, spawn_process, NULL ) == -1 ){ fprintf(stderr, "failed to create thread %d\n", i); } } for(i=0; i<number; i++){ pthread_join(threads, NULL); } return 0; } #ifdef __WIN32__ void init_win32() { /* init win32 socket */ static WSADATA wsa_data; if(WSAStartup((WORD)(1<<8|1), &wsa_data) != 0) exit(1); JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit; FcpJobObject = (HANDLE)CreateJobObject(NULL, NULL); if(FcpJobObject == NULL) exit(1); /* let all processes assigned to this job object * being killed when the job object closed */ if (!QueryInformationJobObject(FcpJobObject, JobObjectExtendedLimitInformation, &limit, sizeof(limit), NULL)) { CloseHandle(FcpJobObject); exit(1); } limit.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; if (!SetInformationJobObject(FcpJobObject, JobObjectExtendedLimitInformation, &limit, sizeof(limit))) { CloseHandle(FcpJobObject); exit(1); } } #endif //__WIN32__ #ifndef __WIN32__ void before_exit(int sig) { signal(SIGTERM, SIG_DFL); /* call child processes to exit */ kill(0, SIGTERM); } #endif int main(int argc, char **argv) { prog_name = strrchr(argv[0], '/'); if(prog_name == NULL) prog_name = strrchr(argv[0], '\\'); if(prog_name == NULL) prog_name = argv[0]; else prog_name++; if(argc == 1) usage(stderr); path = argv[1]; opterr = 0; char* p; for(;;){ int ch; if((ch = getopt_long(argc, argv, opts, longopts, NULL)) == EOF) break; char *av = argv[optind]; switch(ch){ case 'h': usage(stdout); break; case 'v': print_version(); break; case 'n': number = atoi(av); if(number > MAX_PROCESSES){ fprintf(stderr, "exceeds MAX_PROCESSES!\n"); number = MAX_PROCESSES; } break; case 'u': user = av; break; case 'r': root = av; break; case 'g': group = av; break; case 'i': ip = av; break; case 'p': port = atoi(av); break; default: usage(stderr); break; } } #ifdef __WIN32__ init_win32(); #else /* call child processes to exit */ signal(SIGTERM, before_exit); signal(SIGINT, before_exit); signal(SIGABRT, before_exit); #endif int ret; ret = try_to_bind(); if(ret != 0) return ret; ret = start_processes(); if(ret !=0) return ret; #ifdef __WIN32__ CloseHandle(FcpJobObject); WSACleanup(); #endif return 0; }
相关文章推荐
- 32位win7系统下配置IIS遇到php-cgi.exe - FastCGI 进程意外退出问题的解决的方法
- 【转载】IIS出现“HTTP 错误 500.0,C:\php\php-cgi.exe - FastCGI 进程意外退出”解决方法
- 32位win7系统下配置IIS遇到php-cgi.exe - FastCGI 进程意外退出问题的解决的方法
- 完美解决windows+ngnix+phpcgi自动退出的问题
- windows2003远程桌面退出后系统自动注销程序关闭的解决方法
- ubuntu linux qq自动退出关闭的问题解决方法
- 32位win7系统下配置IIS遇到php-cgi.exe - FastCGI 进程意外退出问题的解决办法
- windows 2003远程桌面退出后系统自动注销的解决方法
- nginx在 window下 自动退出 php-cgi
- 关于windows下apache运行php出现httpd.exe错误的解决方法
- windows 2003 server服务自动关闭的解决方法
- nginx在 window下 自动退出 php-cgi
- ubuntu linux qq自动退出关闭的问题解决方法
- 32位win7系统下配置IIS遇到php-cgi.exe - FastCGI 进程意外退出问题的解决办法
- ubuntu linux qq自动退出关闭的问题解决方法
- windows2003远程桌面退出后系统自动注销程序关闭的解决方法
- 完美解决方法:IE8 DEP 为了帮助保护您的计算机,windows 已经关闭了此程序 自动关闭 IE8.0
- Windows Service 2008 R2 远程桌面关闭,自动注销的解决方法
- windows nginx+php 显示no input file specified的解决方法
- "php-cgi.exe - FastCGI 进程意外退出" 的解决办法