Страница 1 из 1

[C++] Apache/PHP process

Добавлено: 2010-07-30 13:23:33
y-ur-i
Я написал PHP etension модуль, который создает объект. Мне нужно reuse-ать этот объект между последовательными запросами от WEB-application. Windows/Apache/PHP работает, а вот Linux/Apache/PHP кажется использует разные процессы для обработки (или создает каждый раз новый процесс), поэтому второй запрос не видит объект созданный предыдущим. Есть ли способ сконфигурировать Linux/Apache/PHP, так чтобы запросами от WEB-application (это разные PHP сктипты) всегда обрабатывались одним и тем же процессом и этот прцесс бы жил пока WEB-application не logout-нулась.
Поможет ли httpd.worker model? /etc/sysconfig/httpd говорит, что httpd.worker model нельзя использовать с PHP.

Re: Apache/PHP process

Добавлено: 2010-07-31 16:38:19
ProFTP
что-то не понятно, это типо многопоточность или взаимодействие с нексколькими сриптами

Re: Apache/PHP process

Добавлено: 2010-08-02 11:42:10
y-ur-i
1. Скажем есть WEB-application с 2-мя запрсами к серверу. По первому запросу на сервере выполняется РНР скрипт 1, а по-второму – скрипт 2.
2. На сервере, есть РНР etension модуль написанный на С++.
3. Скрипты 1 и 2 используют функции этого С++ модуля.
4. В РНР etension модуле есть С++ GLOBAL МАР, кокторый хранит указатели на объекты.
5. Указатель от скрипта к скрипту передается через WEB-application.
Первый скрипт вызывает функцию 1, которая создает объект и добавляет указатель на этот объект в МАР.
Второй скрипт вызывает функцию 2, которая должна использовать этот объект. Так вот скрипт 2 не видит указатель созданный скриптом 1 (GLOBAL МАР пустой).
Я новичок с РНР etension модулями, РНР и Апачем.
Поэтому вопросы:
Можно ли и сделать С++ GLOBAL МАР общим для скриптов?
Еслп да, можно ли и сделать объект созданный первым скриптом видимым из 2-го скрипта?
Если да, то что может быть не так в РНР etension модуле? Или в конфигурации Апача?
Если нет, то надо организовывать интер-процесс communication, чего очень не хочется.

Re: Apache/PHP process

Добавлено: 2010-08-02 19:36:15
ProFTP
давайте вы покажите код С++, и тему мы перенесем в рздел С++? :)

Re: [C++] Apache/PHP process

Добавлено: 2010-08-02 20:51:19
ProFTP
PS: вообще, есть SysV, IPC для взаимодействия скриптов, т.к. семафоры, share memory, и т.д. ... специально сделанное для межпроцессорного взамодействия

Re: [C++] Apache/PHP process

Добавлено: 2010-08-04 14:30:00
y-ur-i
Вот код. Я постарался выбросить все лишнее.

Код: Выделить всё

// db_extphp.cpp
//
#include <Qt/qglobal.h>
#include <QMap>
#include <QString>
#include "lib_db.h"//the CDb object is defined in this library

#ifdef DB_EXT_LIB
# define DB_EXT_EXPORT Q_DECL_EXPORT
#else
# define DB_EXT_EXPORT Q_DECL_IMPORT
#endif

//constants to export
#define DB_EXT_RETURN_VALUE				"ReturnValue"
#define DB_EXT_ERROR_DESCRIPTION			"ErrorDescription"

class DB_EXT_EXPORT CSelector : public QObject
{
	Q_OBJECT
public:
	CSelector(){};
	~CSelector(){};
	QMutex m_mutexDelete;

	CDb m_objDB;//logic is in this object
};

class DB_EXT_EXPORT CConnections : public QObject
{
	Q_OBJECT
public:
	CConnections(){};
	~CConnections();
	long GetSessionID(char *sUser, char *sPswd, char *sDBHost, long nPort, char *sError);
	QMutex m_mutexUseMap;
	QMap<long,CSelector *> m_mapSessions;
};

CConnections::~CConnections()
{
	QMap<long,CSelector *>::iterator pos;

	for(pos=m_mapSessions.begin(); pos != m_mapSessions.end();)
	{
		try{
			pos.value()->m_objDB.logoff();
		}
		catch(...){
		}
		try{
			delete pos.value();
		}
		catch(...){
		}
		pos = m_mapSessions.erase(pos);
	}
}

long CConnections::GetSessionID(char *sUser, char *sPswd, char *sDBHost, long nPort, char *sError)
{
	long i,nID=0;
	CSelector *pSelector=NULL;

	pSelector=new CSelector;//new CDb object is created here
	if(pSelector)
	{
		if(pSelector->m_objDB.login(sUser, sPswd, sDBHost, nPort))
		{
			nID = (long)time(NULL) * 0x9e3779b9;//create session code
			for(i=0;i<2048;++i,++nID)
				if(m_mapSessions.find(nID) == m_mapSessions.end())
					break;
			if(i<2048)
			{
				m_mutexUseMap.lock();
				m_mapSessions.insert(nID, pSelector);
				m_mutexUseMap.unlock();
			}
			else
			{
				nID=0;
				delete pSelector;
				strcpy(sError,"Too many open connections.");
			}
		}
		else
		{
			strncpy(sError,pSelector->m_objDB.getLastError().toAscii().data(),255);
			delete pSelector;
		}
	}
	else
	{
		strcpy(sError,"Not enough memory.");
	}

	return nID;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////

CConnections g_Connections;

#define	GET_SELECTOR	CSelector *pSelector=NULL;\
						g_Connections.m_mutexUseMap.lock();\
						pSelector = g_Connections.m_mapSessions.value(nSessionID);\
						if(!pSelector){\
							add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"Wrong session ID.",1);\
							add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);\
							g_Connections.m_mutexUseMap.unlock();\
							return;\
						}\
\
						QMutexLocker locker(&pSelector->m_mutexDelete);\
						g_Connections.m_mutexUseMap.unlock();\
\

#include "php.h"

ZEND_MODULE_STARTUP_D(DB_EXTPHP);
ZEND_MODULE_SHUTDOWN_D(DB_EXTPHP);

ZEND_FUNCTION(dbLogin);
ZEND_FUNCTION(dbLogout);
ZEND_FUNCTION(dbResetDataFields);
/* compiled function list so Zend knows what's in this module */
zend_function_entry DB_EXTPHP_functions[] = {
   ZEND_FE(dbLogin, NULL)
   ZEND_FE(dbLogout, NULL)
   ZEND_FE(dbResetDataFields, NULL)
   {NULL, NULL, NULL}
};    

/* compiled module information */
zend_module_entry DB_EXTPHP_module_entry = {
    STANDARD_MODULE_HEADER,
    "DB_EXTPHP",
    DB_EXTPHP_functions,
	ZEND_MODULE_STARTUP_N(DB_EXTPHP),
	ZEND_MODULE_SHUTDOWN_N(DB_EXTPHP),
	NULL, NULL, NULL,
    NO_VERSION_YET, STANDARD_MODULE_PROPERTIES
};    

/* implement standard "stub" routine to introduce ourselves to Zend */
ZEND_GET_MODULE(DB_EXTPHP)

ZEND_MODULE_STARTUP_D(DB_EXTPHP)
{

	REGISTER_STRING_CONSTANT("DB_EXT_ERROR_DESCRIPTION", DB_EXT_ERROR_DESCRIPTION, CONST_CS | CONST_PERSISTENT);
	REGISTER_STRING_CONSTANT("DB_EXT_RETURN_VALUE", DB_EXT_RETURN_VALUE, CONST_CS | CONST_PERSISTENT);

	return SUCCESS;
}

ZEND_MODULE_SHUTDOWN_D(DB_EXTPHP)
{
	return SUCCESS;
}

ZEND_FUNCTION(dbLogin){
    char		*sUser=NULL;
    char		*sPswd=NULL;//password
    char		*sDBHost=NULL;
	long		nUser;
	long		nDPswd;
	long		nDBHost;
	long		nPort;

	long		nSessionID;
	char		sError[256];
	zval		*pzResource;
	CSelector	*pSelector=NULL;

	array_init(return_value);

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sssll",
					&sUser, &nUser, &sPswd, &nDPswd, &sDBHost, &nDBHost, &nPort) == FAILURE){

		add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"Wrong parameters passed to the function.",1);
		add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
    }
	else{
		if(!(nSessionID = g_Connections.GetSessionID(sUser,sPswd,sDBHost,nPort,sError))){
			sError[255]=0;
			add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,sError,1);
			add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
		}
		else{
			add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"No error.",1);
			add_assoc_long(return_value,DB_EXT_RETURN_VALUE,nSessionID);
		}
	}
}

ZEND_FUNCTION(dbLogout){
	long		nSessionID;
	CSelector	*pSelector=NULL;

	array_init(return_value);

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &nSessionID) == FAILURE){
		add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"Wrong parameters passed to the function.",1);
		add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
    }
	else{
		g_Connections.m_mutexUseMap.lock();
		pSelector = g_Connections.m_mapSessions.value(nSessionID);
		g_Connections.m_mapSessions.remove(nSessionID);
		g_Connections.m_mutexUseMap.unlock();

		if(pSelector){
			pSelector->m_objDB.logoff();
			delete pSelector;
			add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"No error.",1);
			add_assoc_long(return_value,DB_EXT_RETURN_VALUE,1);
		}
		else{
			add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"Wrong session ID.",1);
			add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
		}
	}
}

ZEND_FUNCTION(dbResetDataFields){
	long	nSessionID;

	array_init(return_value);

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &nSessionID) == FAILURE){
 		add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"Wrong parameters passed to the function.",1);
		add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
       return;//wrong parameters passed
    }

//
	GET_SELECTOR
//
	pSelector->m_objDB.resetDBExtraction();
	if(!pSelector->m_objDB.getLastError().isEmpty()){
		char sError[256];
		sError[255]=0;
		strncpy(sError,pSelector->m_objDB.getLastError().toAscii().data(),255);
		add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,sError,1);
		add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
	}
	else{
		add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,"No error.",1);
		add_assoc_long(return_value,DB_EXT_RETURN_VALUE,1);
	}
}

А вот как я собирался использовать.

Скрипт 1:

Код: Выделить всё

        $hashResult = dbLogin($_POST['User'],$_POST['Password'],$_POST['Host'],$_POST['Port']); 
        if(is_null($hashResult[YE_RETURN_VALUE])){
          echo '<br>';
	      exit ($hashResult[YE_ERROR_DESCRIPTION]); 
	    }else {
	      $nSessionID = $hashResult[YE_RETURN_VALUE];
	    }
Значение $nSessionID передается скрипту 2:

Код: Выделить всё

        $hashResult = dbResetDataFields($nSessionID); 
        if(is_null($hashResult[YE_RETURN_VALUE])){
          echo '<br>', $hashResult[YE_ERROR_DESCRIPTION];
        }
        dbLogout($nSessionID); 

Re: [C++] Apache/PHP process

Добавлено: 2010-08-04 14:42:17
y-ur-i
Пардон, кое-что забыл поменять, не суть, но все-таки...
Скрипт 1:

Код: Выделить всё

    $hashResult = dbLogin($_POST['User'],$_POST['Password'],$_POST['Host'],$_POST['Port']); 
    if(is_null($hashResult[DB_EXT_RETURN_VALUE])){
      echo '<br>';
       exit ($hashResult[DB_EXT_ERROR_DESCRIPTION]); 
    }else {
      $nSessionID = $hashResult[DB_EXT_RETURN_VALUE];
    }
Скрипт 2:

Код: Выделить всё

    $hashResult = dbResetDataFields($nSessionID); 
    if(is_null($hashResult[DB_EXT_RETURN_VALUE])){
      echo '<br>', $hashResult[DB_EXT_ERROR_DESCRIPTION];
    }
    dbLogout($nSessionID);

Re: [C++] Apache/PHP process

Добавлено: 2010-08-18 16:05:17
Dambo
Как то странно вы пишите, в топике пишете про настройки апачей, в 3 сообщении код выставляете,решите в чём будете копаться.
У вас в нём кстати идёт проверка при перезагрузке, могли бы и рассказать что оно вам выдаёт)

Код: Выделить всё

   pSelector->m_objDB.resetDBExtraction();
   if(!pSelector->m_objDB.getLastError().isEmpty()){
      char sError[256];
      sError[255]=0;
      strncpy(sError,pSelector->m_objDB.getLastError().toAscii().data(),255);
      add_assoc_string(return_value,DB_EXT_ERROR_DESCRIPTION,sError,1);
      add_assoc_unset(return_value,DB_EXT_RETURN_VALUE);
   }
"С++ GLOBAL МАР" не понятно мне(гугл с яндаксом тоже разводят руки), что это такое по вашему в приведённом примере кода не ясно, его просто нет.
map у вас единственный находится в вроде бы глобальном объекте g_Connections, в логине и логауте вы к нему обращаетесь и используете от туда сессии от m_mapSessions, а в функции рестарта вы используете не известно откуда взявшегося объекта(из приведённого кода) pSelector и с помощью его уже рестартите...

Re: [C++] Apache/PHP process

Добавлено: 2010-08-18 20:55:12
y-ur-i
Извиняюсь за свою способность формулировать вопросы и постараюсь быть более понятным.

1. Скажем есть WEB-application с 2-мя запросами от клиента к серверу. По первому запросу на сервере выполняется РНР скрипт 1, а по-второму – скрипт 2.
2. На сервере, есть РНР extension модуль написанный на С++.
3. Скрипты 1 и 2 используют функции этого С++ модуля.
4. В РНР extension модуле есть есть глобальный объект g_Connections.
5. WEB-application обращается к серверу для выполнения Скрипт 1.
6. Скрипт 1 вызывает функцию dbLogin.
7. dbLogin вызывает функцию g_Connections.GetSessionID, которая создает CSelector объект и уникальный Id для этого объекта. А также заносит этот объект в g_Connections.m_mapSessions (смотри m_mapSessions.insert(nID, pSelector);). Уникальный Id возвращается в скрипт. Вся логика последующих запросов инкапсулирована в одном из членов CSelector (CDb).
8. Скрипт 1 возвращает уникальный Id в WEB-application клиенту.
9. На этом первое обращение клиента к серверу заканчивается. Объект создан, занесен в map и предполагается быть использован следующими запросами.
10. WEB-application обращается к серверу для выполнения Скрипт 2.
11. Скрипт 2 вызывает функцию dbResetDataFields с уникальным Id параметром полученным от Скрипт 1.
12. Функция dbResetDataFields пытается достать CSelector объект соответстующий этому уникальному Id
(смотри #define GET_SELECTOR макро сразу после CConnections g_Connections;
pSelector = g_Connections.m_mapSessions.value(nSessionID);)
13. На Windows сервере это работает. На Linux сервере
pSelector = g_Connections.m_mapSessions.value(nSessionID);
не находит CSelector объект соответстующий этому уникальному Id.

Я понимаю так: под Windows есть один апач процесс и много thread-ов, поэтому все хорошо. А под Linux есть много апач-процессов и первый скрипт был обработан одним процессом, а второй скрипт другим процессом и поэтом в каждом процессе есть свой глобальный объект CConnections g_Connections. Скрипт 1 в первом процессе добавляет CSelector объект g_Connections.m_mapSessions. А Скрипт 2 пытается достать этот обект из другого процесса и естественно не может.

Вопрос: Можно ли сделать так (сконфигурировать апач), чтобы все скрипты от данного клиента (WEB-application ) обрабатывались тем же апач процессом на Linux сервере.

Re: [C++] Apache/PHP process

Добавлено: 2010-08-19 9:47:48
Dambo
Вопрос: Можно ли сделать так (сконфигурировать апач), чтобы все скрипты от данного клиента (WEB-application ) обрабатывались тем же апач процессом на Linux сервере.
Не в том форуме пишите вопрос, утилитой ps(почитайте man ps или http://ru.wikipedia.org/wiki/Ps,
конкретно для фряхи http://www.freebsd.org/cgi/man.cgi?query=ps&sektion=1) можно посмотреть процессы запущенные на сервере, это по поводу количества апачевых процессов.
По поводу решения проблемы могу посоветовать только, создания приложения.
Заранее запущенного на сервере или сделать проверку в 1 скрипте на запуск, а скриптом 2 посылать сигнал с идентификатором, вы всё равно используете qt, сигналы и процессы в ней реализовать очень просто.

Re: [C++] Apache/PHP process

Добавлено: 2010-09-02 16:07:18
BlackCat
Присоединюсь к Dambo.
Не сохранение данных между запросами - это фундаментальная особенность скриптовых языков и нарушать её - не самая лучшая идея. Это заложено ещё в HTTP-протоколе, где клиент по мере необходимости обращается к серверу, а не подключен постоянно. Постоянное соединение (сессия) - это всего лишь абстракция.
Если данные требуется сохранять между запросами, то для этого используют сессии и сериализацию данных. Если по каким-либо причинам такой вариант не подходит, то необходимо писать свой демон. Он или сам будет обрабатывать все запросы пользователей (т.е. реализовывать HTTP-протокол) или в качестве фронтенда должен использоваться какой-то HTTP-сервер (прим. Apache), связывающийся с вашим демоном при обработке запросов пользователей.

Re: [C++] Apache/PHP process

Добавлено: 2010-09-02 16:32:12
y-ur-i
Я понял. Спасибо за информацию.