検索
ホームページphp教程php手册windows下php-cgi进程守护

windows下php-cgi进程守护

Jun 06, 2016 pm 07:31 PM
phpphp-cgiwindowsプロセス

php在linux,unix下有php-fpm,spawn-fcgi等进程守护程序,但是在window下没有。 一般会以下命令启动C:/php5/php-cgi.exe-b127.0.0.1:9000-cC:/php5/php.ini 但是这样受限于php-cgi的PHP_FCGI_MAX_REQUESTS环境变量,默认处理500次后自动退出php-cgi.加之一些非

       php在linux,unix下有php-fpm,spawn-fcgi等进程守护程序,但是在window下没有。
一般会以下命令启动 C:/php5/php-cgi.exe -b 127.0.0.1:9000 -c C:/php5/php.ini 
但是这样受限于php-cgi的PHP_FCGI_MAX_REQUESTS环境变量,默认处理500次后自动退出php-cgi.加之一些非正常原因的异常退出,都会导致php-cgi.exe的退出。所有在window需要进程守护程序,当php-cgi退出后自动打开新的php-cgi进程。
      注意事项:windows建议关闭Dr. Watson,否则 异常的php-cgi无法正常退出。 
http://support.microsoft.com/kb/188296/zh-cn
// FastCGIHelper.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#pragma comment(lib, "ws2_32.lib")

const PCHAR cServiceName="WinFastCGIHelper";

HANDLE hJob;

INT  icount;
INT	 iport;
CHAR ipbuf[32];
CHAR cmdbuf[256];

//---------------------------------------------------------------------------
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;

void Install(void);
void Uninstall(void);
void ServiceMain(int argc, char** argv);
void ThreadProc(LPVOID pParam);
void ControlHandler(DWORD request);

//---------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
    if (argc>1 && _stricmp(argv[1],"/i")==0)
    {
        Install();
    }
    else if (argc>1 && _stricmp(argv[1],"/u")==0)
    {
        Uninstall();
    }
    else
    {
        SERVICE_TABLE_ENTRY ServiceTable[2];
        ServiceTable[0].lpServiceName = cServiceName;
        ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

        ServiceTable[1].lpServiceName = NULL;
        ServiceTable[1].lpServiceProc = NULL;

        ::StartServiceCtrlDispatcher(ServiceTable);
    }

	return 0;
}

void ServiceMain(int argc, char** argv)
{
    ServiceStatus.dwServiceType  =SERVICE_WIN32;
    ServiceStatus.dwCurrentState =SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted  = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode     = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;
    ServiceStatus.dwWaitHint   = 0;

    hStatus = ::RegisterServiceCtrlHandler(cServiceName, (LPHANDLER_FUNCTION)ControlHandler);
    if (hStatus == NULL)    return;

    if (GetLastError()!=NO_ERROR)
	{ 
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ::SetServiceStatus(hStatus, &ServiceStatus);
        return; 
    }

	CHAR cConfigName[256];
	ZeroMemory(cConfigName,256);
	DWORD dwSize=GetModuleFileName(NULL,cConfigName,256);
    while(dwSize>0 && cConfigName[dwSize]!='\\')
        cConfigName[dwSize--]=0;

	strcat_s(cConfigName,"config.ini");

	icount=GetPrivateProfileInt("setup","CmdCount",1,cConfigName);
	GetPrivateProfileString("setup","CmdPath","",cmdbuf,256,cConfigName);
	
	if(icount<1) icount=1;
	if(icount>32) icount=32;

	iport =GetPrivateProfileInt("setup","Port",9000,cConfigName);
	GetPrivateProfileString("setup","IP","127.0.0.1",ipbuf,32,cConfigName);

	WSADATA wsa_data; 
	WSAStartup(0x0202, &wsa_data);

	SOCKADDR_IN listen_addr;
	listen_addr.sin_family		=AF_INET;
	listen_addr.sin_addr.S_un.S_addr= inet_addr(ipbuf);
	listen_addr.sin_port		= htons(iport);

	DWORD s=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
	if(bind(s, (struct sockaddr*)&listen_addr, sizeof(struct sockaddr_in)) || listen(s,16) ){
        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
        ::SetServiceStatus(hStatus, &ServiceStatus);
        return; 
	}
	
	CHAR strtmp[128];
	ZeroMemory(strtmp,128);

	GetPrivateProfileString("env","PHPRC",".",strtmp,127,cConfigName);
	SetEnvironmentVariable("PHPRC",strtmp);

	GetPrivateProfileString("env","PHP_FCGI_MAX_REQUESTS","5000",strtmp,127,cConfigName);
	SetEnvironmentVariable("PHP_FCGI_MAX_REQUESTS",strtmp);

	hJob=CreateJobObject(NULL,NULL);

	JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit;
	QueryInformationJobObject(hJob, JobObjectExtendedLimitInformation, &limit, sizeof(limit), NULL);
	limit.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
	SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &limit, sizeof(limit));

	ServiceStatus.dwCurrentState = SERVICE_RUNNING;
    SetServiceStatus(hStatus, &ServiceStatus);

	for(int i=0;i<icount;i++)
		CloseHandle(CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadProc,(LPVOID)s,0,0));
	
	WaitForSingleObject(hJob, INFINITE);
	
	closesocket(s);
	WSACleanup();
    
    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
    SetServiceStatus(hStatus, &ServiceStatus);
}
//---------------------------------------------------------------------------
void  ThreadProc(LPVOID pParam)
{
	STARTUPINFO si; 
	PROCESS_INFORMATION pi;   

	while(ServiceStatus.dwCurrentState == SERVICE_RUNNING)
	{
		ZeroMemory(&si,sizeof(STARTUPINFO));
		ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));

		si.cb = sizeof(STARTUPINFO);
		si.dwFlags 	= STARTF_USESTDHANDLES;
		si.hStdInput  = (HANDLE)pParam;
		si.hStdOutput = INVALID_HANDLE_VALUE;
		si.hStdError  = INVALID_HANDLE_VALUE;

		if(0==CreateProcess(NULL,cmdbuf,NULL,NULL,TRUE, 
			CREATE_NO_WINDOW | CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB ,NULL,NULL,&si,&pi))
				break;

		AssignProcessToJobObject(hJob, pi.hProcess);
		ResumeThread(pi.hThread);

		WaitForSingleObject(pi.hProcess, INFINITE);

		CloseHandle( pi.hProcess);
		CloseHandle( pi.hThread );
	}
}
//---------------------------------------------------------------------------
void ControlHandler(DWORD request)
{
   switch(request)
   {
      case SERVICE_CONTROL_STOP:
        ServiceStatus.dwWin32ExitCode = 0;
        ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
        SetServiceStatus(hStatus, &ServiceStatus);

		CloseHandle(hJob);
        return;

      case SERVICE_CONTROL_SHUTDOWN:
        ServiceStatus.dwWin32ExitCode = 0;
        ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
        SetServiceStatus(hStatus, &ServiceStatus);

		CloseHandle(hJob);
        return;
    } 

    ::SetServiceStatus (hStatus, &ServiceStatus);
}
//---------------------------------------------------------------------------
void Install(void)
{
    char  szFilePath[256];
    SC_HANDLE hSCM,hService;

    ZeroMemory(szFilePath,256);
    GetModuleFileName(NULL,szFilePath,256);

    hSCM=::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	SC_LOCK sclLock = LockServiceDatabase(hSCM); 

    hService = ::CreateService( hSCM, cServiceName, cServiceName,
        SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,
            SERVICE_ERROR_NORMAL, szFilePath, NULL, NULL,NULL, NULL, NULL);

	SERVICE_DESCRIPTION sdBuf;
	sdBuf.lpDescription = "php fastcgi process helper for windows";
	ChangeServiceConfig2(hService,SERVICE_CONFIG_DESCRIPTION,&sdBuf);

	::CloseServiceHandle(hService);   
	::UnlockServiceDatabase(sclLock); 

    ::CloseServiceHandle(hSCM);
    printf("Service Install OK !!!");
}

//---------------------------------------------------------------------------
void Uninstall(void)
{
    SERVICE_STATUS sStatus ;
    SC_HANDLE hSCM=::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    SC_HANDLE hService=::OpenService(hSCM, cServiceName, SERVICE_STOP | DELETE);

    if (hService==NULL)
    {
        printf("Service Open Error !!!");
    }
    else
    {
        ::ControlService(hService, SERVICE_CONTROL_STOP, &sStatus);
        ::DeleteService(hService);
        printf("Service Uninstall OK !!!");
    }

    ::CloseServiceHandle(hService);
    ::CloseServiceHandle(hSCM);
}
//---------------------------------------------------------------------------
声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境