Http://down.chinaz.com/server/201111/1334_1.htm
Php-cgi.exe in the Windows+nginx platform often automatically exit, most of the solutions found on the Internet are similar to the above batch (code as follows) file temporary solution, but if the user log on the site, the user will suddenly hang out.
A batch File
@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 process is missing, now add 5 processes RunHiddenConsole.exe php\php-cgi.exe-b 127.0.0.1:9000-c Php\php.ini Run HiddenConsole.exe php\php-cgi.exe-b 127.0.0.1:9000-c Php\php.ini RunHiddenConsole.exe php\php-cgi.exe-b 00-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 normal operation! Ping 127.1-n 8 goto main
The best solution is to use the PHP-CGI process Manager under Windows, which requires the pthreadGC2.dll to be used by the process manager. source code and compile files are available at the end of this article. Tested to support WIN32 and linux-x86 platforms. For people with PHP, with this thing to maintain a certain number of processes, you will be able to subdue the frequent collapse of the exit php-cgi.
The following are the action parameters for the XXFPM process Manager:
USAGE:XXFPM path [-n] [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 v Ersion Information and exit
The first to write a more standard terminal application, I was looking at some of the source code in Cygwin, and then learned how to use Getopt, is written more standard, but the code is not short.
Use examples:
XXFPM z:/php5/php-cgi.exe-n 5-p 8080
Someone asked how to add parameters to the program. This is not difficult, use double quotes, the path to use "/" instead of "\". For example, to specify the path to PHP.ini, you can use the following example:
XXFPM "Z:/php5/php-cgi.exe-c Z:/php5/php.ini"-N 5-i 127.0.0.1-p 8080
Maintenance Process principle:
Use CreateProcess to create processes on Windows, use wait for single object to end the process, use fork and execl to create processes on Linux, and use Waitpid to wait for the process to end. There are more versions of Linux you can set process limits when you create a subprocess and be able to run as a limited user.
When the process manager is closed, all of the child processes it creates must also be closed. Windows use Jobobject this thing to handle the process and manager of the process of association, thanks to the information provided by Iceboy. On Linux, you end the subprocess by capturing the shutdown signal and then sending sigterm to all the child processes. For more details, see Source code:
#ifdef __win32__ #ifndef _win32_winnt #define _WIN32_WINNT 0x0500 #endif//_win32_winnt #include <windows.h> #incl Ude <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__ #in Clude <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", R Equired_argument, NULL, ' n '}, {"IP", required_argument, NULL, ' I '}, {"Port", required_argument, NULL, ' P '}, {"User", re Quired_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 P Rocesses.\n "\ n" ""-N,--number number of processes to keep\n ""-I,--IP IP address to bind\n ""-P,--por T port to bind, the default is 8000\n ""-u,--user start processes using specified Linux user\n ""-G,--group St Art 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 xiaoxia.org\n\ '%s
\n\ ", Prog_name, version, __date__);
Exit (0);
The 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 GR OUP *GRp = NULL;
struct passwd *pwd = NULL; if (*user) {if (NULL = = PWD = Getpwnam (user)) {fprintf (stderr, "[fcgi]%s%s\n", "can ' t find username", use
R);
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) {Fprin
TF (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's 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 |=