[C++] Apache/PHP process

Модератор: Fastman

Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

[C++] Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-07-30 13:23:33

Я написал 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.

Хостинговая компания Host-Food.ru
Хостинг HostFood.ru
 

Услуги хостинговой компании Host-Food.ru

Хостинг HostFood.ru

Тарифы на хостинг в России, от 12 рублей: https://www.host-food.ru/tariffs/hosting/
Тарифы на виртуальные сервера (VPS/VDS/KVM) в РФ, от 189 руб.: https://www.host-food.ru/tariffs/virtualny-server-vps/
Выделенные сервера, Россия, Москва, от 2000 рублей (HP Proliant G5, Intel Xeon E5430 (2.66GHz, Quad-Core, 12Mb), 8Gb RAM, 2x300Gb SAS HDD, P400i, 512Mb, BBU):
https://www.host-food.ru/tariffs/vydelennyi-server-ds/
Недорогие домены в популярных зонах: https://www.host-food.ru/domains/

Аватара пользователя
ProFTP
подполковник
Сообщения: 3388
Зарегистрирован: 2008-04-13 1:50:04
Откуда: %&й
Контактная информация:

Re: Apache/PHP process

Непрочитанное сообщение ProFTP » 2010-07-31 16:38:19

что-то не понятно, это типо многопоточность или взаимодействие с нексколькими сриптами
Pеrl FAQ
perl -e 'print join"",map $$_[rand@$_],([0..9,'a'..'z','A'..'Z'])x30'
ИзображениеИзображение

y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

Re: Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-08-02 11:42:10

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, чего очень не хочется.

Аватара пользователя
ProFTP
подполковник
Сообщения: 3388
Зарегистрирован: 2008-04-13 1:50:04
Откуда: %&й
Контактная информация:

Re: Apache/PHP process

Непрочитанное сообщение ProFTP » 2010-08-02 19:36:15

давайте вы покажите код С++, и тему мы перенесем в рздел С++? :)
Pеrl FAQ
perl -e 'print join"",map $$_[rand@$_],([0..9,'a'..'z','A'..'Z'])x30'
ИзображениеИзображение

Аватара пользователя
ProFTP
подполковник
Сообщения: 3388
Зарегистрирован: 2008-04-13 1:50:04
Откуда: %&й
Контактная информация:

Re: [C++] Apache/PHP process

Непрочитанное сообщение ProFTP » 2010-08-02 20:51:19

PS: вообще, есть SysV, IPC для взаимодействия скриптов, т.к. семафоры, share memory, и т.д. ... специально сделанное для межпроцессорного взамодействия
Pеrl FAQ
perl -e 'print join"",map $$_[rand@$_],([0..9,'a'..'z','A'..'Z'])x30'
ИзображениеИзображение

y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

Re: [C++] Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-08-04 14:30:00

Вот код. Я постарался выбросить все лишнее.

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

// 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); 

y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

Re: [C++] Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-08-04 14:42:17

Пардон, кое-что забыл поменять, не суть, но все-таки...
Скрипт 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);

Dambo
ефрейтор
Сообщения: 61
Зарегистрирован: 2009-11-27 22:29:58

Re: [C++] Apache/PHP process

Непрочитанное сообщение Dambo » 2010-08-18 16:05:17

Как то странно вы пишите, в топике пишете про настройки апачей, в 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 и с помощью его уже рестартите...

y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

Re: [C++] Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-08-18 20:55:12

Извиняюсь за свою способность формулировать вопросы и постараюсь быть более понятным.

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 сервере.

Dambo
ефрейтор
Сообщения: 61
Зарегистрирован: 2009-11-27 22:29:58

Re: [C++] Apache/PHP process

Непрочитанное сообщение Dambo » 2010-08-19 9:47:48

Вопрос: Можно ли сделать так (сконфигурировать апач), чтобы все скрипты от данного клиента (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, сигналы и процессы в ней реализовать очень просто.

Аватара пользователя
BlackCat
прапорщик
Сообщения: 469
Зарегистрирован: 2007-10-16 22:40:42

Re: [C++] Apache/PHP process

Непрочитанное сообщение BlackCat » 2010-09-02 16:07:18

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

y-ur-i
проходил мимо
Сообщения: 6
Зарегистрирован: 2010-07-30 12:51:47

Re: [C++] Apache/PHP process

Непрочитанное сообщение y-ur-i » 2010-09-02 16:32:12

Я понял. Спасибо за информацию.