windows下的Nginx和php搭配 php-cgi.exe自动关闭退出解决方法

来源:互联网 发布:hex下载到单片机 编辑:程序博客网 时间:2024/04/27 23:13

http://down.chinaz.com/server/201111/1334_1.htm

     php-cgi.exe在windows+nginx平台下经常自动退出,网上搜到的大部分解决方法都是类似上面的批处理(代码如下)文件临时解决一下,但如果用户在网站登录的话,用户就会突然挂掉。

一个批处理文件

@echo off:mainset jinchengshuliang=0set jinchengshuliangxiaxian=2for /f %%i in ('tasklist /nh^|findstr /i /s /c:"php-cgi.exe"') do set /a jinchengshuliang+=1if %jinchengshuliang% lss %jinchengshuliangxiaxian% (   goto youwenti) else (goto meiwenti)  :youwentiecho 进程丢失,现在添加5个进程RunHiddenConsole.exe  php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.iniRunHiddenConsole.exe  php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.iniRunHiddenConsole.exe  php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.iniRunHiddenConsole.exe  php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.iniRunHiddenConsole.exe  php\php-cgi.exe -b 127.0.0.1:9000 -c php\php.iniping 127.1 -n 8goto main:meiwentiecho 正常运行中!ping 127.1 -n 8goto 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)#endifHANDLE 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 1024static 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);}#endifint 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;}

0 0
原创粉丝点击