zoukankan      html  css  js  c++  java
  • 完美解决windows+ngnix+phpcgi自动退出的问题

    [摘要]在windows下搭建nginx+php环境时,php-cgi.exe会经常性的自动关闭退出,本文介绍通过使用xxfpm进程管理器管理php-cgi.exe。

        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  phpphp-cgi.exe -b 127.0.0.1:9000 -c phpphp.ini
    RunHiddenConsole.exe  phpphp-cgi.exe -b 127.0.0.1:9000 -c phpphp.ini
    RunHiddenConsole.exe  phpphp-cgi.exe -b 127.0.0.1:9000 -c phpphp.ini
    RunHiddenConsole.exe  phpphp-cgi.exe -b 127.0.0.1:9000 -c phpphp.ini
    RunHiddenConsole.exe  phpphp-cgi.exe -b 127.0.0.1:9000 -c phpphp.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啦!

    下载地址:http://down.chinaz.com/soft/31157.htm

    以下是xxfpm进程管理器的操作参数:

     1 Usage: xxfpm path [-n number] [-i ip] [-p port]
     2 Manage FastCGI processes.
     3 
     4 -n, --number number of processes to keep
     5 -i, --ip ip address to bind
     6 -p, --port port to bind, default is 8000
     7 -u, --user start processes using specified linux user
     8 -g, --group start processes using specified linux group
     9 -r, --root change root direcotry for the processes
    10 -h, --help output usage information and exit
    11 -v, --version output version information and exit
    View Code

    第一个写得比较标准的终端应用程序,我是看了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来结束子进程。详见源代码:

      1 #ifdef __WIN32__
      2 
      3 #ifndef _WIN32_WINNT
      4 #define _WIN32_WINNT 0x0500
      5 #endif //_WIN32_WINNT
      6 
      7 #include <windows.h>
      8 #include <winsock.h>
      9 #include <wininet.h>
     10 #define SHUT_RDWR SD_BOTH
     11 
     12 #ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
     13 #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE (0x2000)
     14 #endif
     15 HANDLE FcpJobObject;
     16 
     17 #else
     18 
     19 #include <sys/socket.h>
     20 #include <sys/wait.h>
     21 #include <fcntl.h>
     22 #include <arpa/inet.h>
     23 #include <grp.h>
     24 #include <pwd.h>
     25 #include <unistd.h>
     26 #define closesocket close
     27 
     28 #endif //__WIN32__
     29 
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <getopt.h>
     34 #include <string.h>
     35 #include <pthread.h>
     36 #include <errno.h>
     37 
     38 #define MAX_PROCESSES 1024
     39 static const char version[] = "$Revision: 0.01 $";
     40 static char* prog_name;
     41 int number = 1;
     42 int port = 8000;
     43 char *ip = "127.0.0.1";
     44 char *user = "";
     45 char *root = "";
     46 char *path = "";
     47 char *group = "";
     48 int listen_fd;
     49 struct sockaddr_in listen_addr;
     50 int process_fp[MAX_PROCESSES];
     51 int process_idx = 0;
     52 pthread_t threads[MAX_PROCESSES];
     53 
     54 static struct option longopts[] =
     55 {
     56  {"help", no_argument, NULL, 'h'},
     57  {"version", no_argument, NULL, 'v'},
     58  {"number", required_argument, NULL, 'n'},
     59  {"ip", required_argument, NULL, 'i'},
     60  {"port", required_argument, NULL, 'p'},
     61  {"user", required_argument, NULL, 'u'},
     62  {"group", required_argument, NULL, 'g'},
     63  {"root", required_argument, NULL, 'r'},
     64  {NULL, 0, NULL, 0}
     65 };
     66 
     67 static char opts[] = "hvnipugr";
     68 
     69 static void usage(FILE* where)
     70 {
     71  fprintf(where, ""
     72   "Usage: %s path [-n number] [-i ip] [-p port]
    "
     73   "Manage FastCGI processes.
    "
     74   "
    "
     75   " -n, --number  number of processes to keep
    "
     76   " -i, --ip      ip address to bind
    "
     77   " -p, --port    port to bind, default is 8000
    "
     78   " -u, --user    start processes using specified linux user
    "
     79   " -g, --group   start processes using specified linux group
    "
     80   " -r, --root    change root direcotry for the processes
    "
     81   " -h, --help    output usage information and exit
    "
     82   " -v, --version output version information and exit
    "
     83   "", prog_name);
     84  exit(where == stderr ? 1:0);
     85 }
     86 
     87 static void print_version()
     88 {
     89  printf("%s %s
    
     90 FastCGI Process Manager
    
     91 Copyright 2010 Xiaoxia.org
    
     92 Compiled on %s
    
     93 ", prog_name, version, __DATE__);
     94  exit(0);
     95 }
     96 
     97 static int try_to_bind()
     98 {
     99  listen_addr.sin_family = PF_INET;
    100  listen_addr.sin_addr.s_addr = inet_addr( ip );
    101  listen_addr.sin_port = htons( port );
    102  listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    103  
    104  if (-1 == bind(listen_fd, (struct sockaddr*)&listen_addr, sizeof(struct sockaddr_in)) ) {
    105   fprintf(stderr, "failed to bind %s:%d
    ", ip, port );
    106   return -1;
    107  }
    108  
    109  listen(listen_fd, MAX_PROCESSES);
    110  return 0;
    111 }
    112 
    113 static void* spawn_process(void* arg)
    114 {
    115  int idx = process_idx ++, ret;
    116  while(1){
    117 #ifdef __WIN32__
    118   STARTUPINFO si={0};
    119   PROCESS_INFORMATION pi={0};
    120   ZeroMemory(&si,sizeof(STARTUPINFO));
    121   si.cb = sizeof(STARTUPINFO);
    122   si.dwFlags = STARTF_USESTDHANDLES;
    123   si.hStdInput  = (HANDLE)listen_fd;
    124   si.hStdOutput = INVALID_HANDLE_VALUE;
    125   si.hStdError  = INVALID_HANDLE_VALUE;
    126   if(0 == (ret=CreateProcess(NULL, path,
    127    NULL,NULL,
    128    TRUE, CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB,
    129    NULL,NULL,
    130    &si,&pi)) ){
    131    fprintf(stderr, "failed to create process %s, ret=%d
    ", path, ret);
    132    return NULL;
    133   }
    134   
    135   /* Use Job Control System */
    136   if(!AssignProcessToJobObject(FcpJobObject, pi.hProcess)){
    137    TerminateProcess(pi.hProcess, 1);
    138    CloseHandle(pi.hProcess);
    139    CloseHandle(pi.hThread);
    140    return NULL;
    141   }
    142   
    143   if(!ResumeThread(pi.hThread)){
    144    TerminateProcess(pi.hProcess, 1);
    145    CloseHandle(pi.hProcess);
    146    CloseHandle(pi.hThread);
    147    return NULL;
    148   }
    149   
    150   process_fp[idx] = (int)pi.hProcess;
    151   WaitForSingleObject(pi.hProcess, INFINITE);
    152   process_fp[idx] = 0;
    153   CloseHandle(pi.hThread);
    154 #else
    155   ret = fork();
    156   switch(ret){
    157   case 0:{ //child
    158    /* change uid from root to other user */
    159    if(getuid()==0){ 
    160                 struct group *grp = NULL;
    161                 struct passwd *pwd = NULL;
    162     if (*user) {
    163      if (NULL == (pwd = getpwnam(user))) {
    164       fprintf(stderr, "[fcgi] %s %s
    ", "can't find username", user);
    165       exit(-1);
    166      }
    167 
    168      if (pwd->pw_uid == 0) {
    169       fprintf(stderr, "[fcgi] %s
    ", "what? dest uid == 0?" );
    170       exit(-1);
    171      }
    172     }
    173 
    174     if (*group) {
    175      if (NULL == (grp = getgrnam(group))) {
    176       fprintf(stderr, "[fcgi] %s %s
    ", "can't find groupname", group);
    177       exit(1);
    178      }
    179 
    180      if (grp->gr_gid == 0) {
    181       fprintf(stderr, "[fcgi] %s
    ", "what? dest gid == 0?" );
    182       exit(1);
    183      }
    184      /* do the change before we do the chroot() */
    185      setgid(grp->gr_gid);
    186      setgroups(0, NULL);
    187 
    188      if (user) {
    189       initgroups(user, grp->gr_gid);
    190      }
    191     }
    192     if (*root) {
    193      if (-1 == chroot(root)) {
    194       fprintf(stderr, "[fcgi] %s %s
    ", "can't change root", root);
    195       exit(1);
    196      }
    197      if (-1 == chdir("/")) {
    198       fprintf(stderr, "[fcgi] %s %s
    ", "can't change dir to", root);
    199       exit(1);
    200      }
    201     }
    202 
    203     /* drop root privs */
    204     if (*user) {
    205      setuid(pwd->pw_uid);
    206     }
    207    }
    208    
    209    int max_fd = 0, i=0;
    210    // Set stdin to listen_fd
    211    close(STDIN_FILENO);
    212    dup2(listen_fd, STDIN_FILENO);
    213    close(listen_fd);
    214    // Set stdout and stderr to dummy fd
    215    max_fd = open("/dev/null", O_RDWR);
    216    close(STDERR_FILENO);
    217    dup2(max_fd, STDERR_FILENO);
    218    close(max_fd);
    219    max_fd = open("/dev/null", O_RDWR);
    220    close(STDOUT_FILENO);
    221    dup2(max_fd, STDOUT_FILENO);
    222    close(max_fd);
    223    // close other handles
    224    for(i=3; i<max_fd; i++)
    225     close(i);
    226    char *b = malloc(strlen("exec ") + strlen(path) + 1);
    227    strcpy(b, "exec ");
    228    strcat(b, path);
    229    
    230    /* exec the cgi */
    231    execl("/bin/sh", "sh", "-c", b, (char *)NULL);
    232    exit(errno);
    233    break;
    234   }
    235   case -1:
    236    fprintf(stderr, "[fcgi] fork failed
    ");
    237    return NULL;
    238   default:{
    239    struct timeval tv = { 0, 100 * 1000 };
    240    int status;
    241    select(0, NULL, NULL, NULL, &tv);
    242    switch(waitpid(ret, &status, WNOHANG)){
    243    case 0:
    244     printf("[fcg] spawned process %s: %d
    ", path, ret);
    245     break;
    246    case -1:
    247     fprintf(stderr, "[fcgi] waitpid failed
    ");
    248     return NULL;
    249    default:
    250     if (WIFEXITED(status)) {
    251       fprintf(stderr, "[fcgi] child exited with: %d
    ", WEXITSTATUS(status));
    252     } else if (WIFSIGNALED(status)) {
    253       fprintf(stderr, "[fcgi] child signaled: %d
    ", WTERMSIG(status));
    254     } else {
    255       fprintf(stderr, "[fcgi] child died somehow: %d
    ", status);
    256     }
    257     return NULL;
    258    }
    259    //wait for child process to exit
    260    process_fp[idx] = ret;
    261    waitpid(ret, &status, 0);
    262    process_fp[idx] = 0;
    263   }
    264   }
    265 #endif
    266  }
    267 }
    268 
    269 static int start_processes()
    270 {
    271  int i;
    272  pthread_attr_t attr;
    273  pthread_attr_init(&attr);
    274  pthread_attr_setstacksize(&attr, 64*1024); //64KB
    275  for(i=0; i<number; i++){
    276   if( pthread_create( &threads, &attr, spawn_process, NULL ) == -1 ){
    277    fprintf(stderr, "failed to create thread %d
    ", i);
    278   }
    279  }
    280  
    281  for(i=0; i<number; i++){
    282   pthread_join(threads, NULL);
    283  }
    284  return 0;
    285 }
    286 
    287 #ifdef __WIN32__
    288 void init_win32()
    289 {
    290  /* init win32 socket */
    291  static WSADATA wsa_data; 
    292  if(WSAStartup((WORD)(1<<8|1), &wsa_data) != 0)
    293   exit(1);
    294  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit;
    295  FcpJobObject = (HANDLE)CreateJobObject(NULL, NULL);
    296  if(FcpJobObject == NULL) 
    297   exit(1);
    298  
    299  /* let all processes assigned to this job object
    300   * being killed when the job object closed */
    301  if (!QueryInformationJobObject(FcpJobObject, JobObjectExtendedLimitInformation, &limit, sizeof(limit), NULL)) {
    302   CloseHandle(FcpJobObject);
    303   exit(1);
    304  }
    305 
    306  limit.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    307 
    308  if (!SetInformationJobObject(FcpJobObject, JobObjectExtendedLimitInformation, &limit, sizeof(limit))) {
    309   CloseHandle(FcpJobObject);
    310   exit(1);
    311  }
    312 }
    313 #endif //__WIN32__
    314 
    315 #ifndef __WIN32__
    316 void before_exit(int sig)
    317 {
    318  signal(SIGTERM, SIG_DFL);
    319  /* call child processes to exit */
    320  kill(0, SIGTERM);
    321 }
    322 #endif
    323 
    324 int main(int argc, char **argv)
    325 {
    326  prog_name = strrchr(argv[0], '/');
    327  if(prog_name == NULL)
    328   prog_name = strrchr(argv[0], '\');
    329  if(prog_name == NULL)
    330   prog_name = argv[0];
    331  else
    332   prog_name++;
    333  
    334  if(argc == 1)
    335   usage(stderr);
    336  
    337  path = argv[1];
    338  
    339  opterr = 0;
    340  
    341  char* p;
    342 
    343  for(;;){
    344   int ch;
    345   if((ch = getopt_long(argc, argv, opts, longopts, NULL)) == EOF)
    346    break;
    347   char *av = argv[optind];
    348   switch(ch){
    349   case 'h':
    350    usage(stdout);
    351    break;
    352   case 'v':
    353    print_version();
    354    break;
    355   case 'n':
    356    number = atoi(av);
    357    if(number > MAX_PROCESSES){
    358     fprintf(stderr, "exceeds MAX_PROCESSES!
    ");
    359     number = MAX_PROCESSES;
    360    }
    361    break;
    362   case 'u':
    363    user = av;
    364    break;
    365   case 'r':
    366    root = av;
    367    break;
    368   case 'g':
    369    group = av;
    370    break;
    371   case 'i':
    372    ip = av;
    373    break;
    374   case 'p':
    375    port = atoi(av);
    376    break;
    377   default:
    378    usage(stderr);
    379    break;
    380   }
    381  }
    382 
    383 #ifdef __WIN32__
    384  init_win32();
    385 #else
    386  /* call child processes to exit */
    387  signal(SIGTERM, before_exit);
    388  signal(SIGINT, before_exit);
    389  signal(SIGABRT, before_exit);
    390 #endif
    391  
    392  int ret;
    393  ret = try_to_bind();
    394  if(ret != 0)
    395   return ret;
    396  ret = start_processes();
    397  if(ret !=0)
    398   return ret;
    399  
    400  
    401 #ifdef __WIN32__
    402  CloseHandle(FcpJobObject);
    403  WSACleanup();
    404 #endif
    405  return 0;
    406 }
    View Code

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

  • 相关阅读:
    简介.Net对象序列化.txt
    如何在Web页面退出前提示用户保存数据?
    如何将图片存储到数据库中
    页面回车键响应,onkeydown事件
    用C#创建Windows服务(Windows Services)
    解决“Visual Studio 要求设计器使用文件中的第一个类。移动类代码使之成为文件中的第一个类,然后尝试重新加载设计器。”方法
    动态创建htm元素并添加到document中
    如何在Asp.net的Header中添加/title/Meta tages/CSS
    无法打开项目文件,“d:\web\webapp.csproj”,此安装不支持该项目类型
    用Intelligencia.UrlRewriter实现URL重写
  • 原文地址:https://www.cnblogs.com/fogwang/p/5507594.html
Copyright © 2011-2022 走看看