PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Описание: Кеш сервер и клиент для демонстрации работы с сетью
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 14:00:04
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Приветствую, как и обещал, привожу пример кеша на PHP. Сделано это не как попытка создания быстрого кеша, который может быть реально использован по назначению (то есть, ускорению приложения), поскольку быстрота исполнения интерпретируемого кода оставляет желать лучшего.
Однако же концепция, которую я вкладываю в понятие "кеш", должна быть понятна на данном примере. Кроме того, для изучения может быть полезен просмотр кода - в плане работы с сетью через сокеты. Пример достаточно прост, не имеет множества вещей, которые были бы полезны (полной обработки ошибок, или, например, попыток повторных соединений), но, так как в любом случае интерес этот код может представлять лишь академический, а не практический, я не углублялся в такие детали.

Как это работает. Очень просто - существует кеш-сервер, который слушает входящие соединения на предопределенном порту. Он обрабатывает клиентов, которые с ним соединяются, и, если те шлют команды по протоколу, который он понимает, делает всю полезную работу - хранит кеш, предоставляет значение по ключу и т.п. Код сервера:
PHP:
скопировать код в буфер обмена
  1. class Cache_Server
  2. {
  3.     const PARSER_RAW_SECTION_COMMAND    = 'raw_command';
  4.     const PARSER_RAW_SECTION_DATA       = 'raw_data';
  5.    
  6.     const HANDLER_COMMAND_COMMON_PREFIX = '_hook_';
  7.     const HANDLER_COMMAND_SET_KEY       = 'key';
  8.     const HANDLER_COMMAND_SET_DATA      = 'data';
  9.     const HANDLER_COMMAND_SET_SUCCESS   = 1;
  10.     const HANDLER_COMMAND_SET_FAILURE   = 0;
  11.    
  12.     const SOCKET_BLOCK_READ_SIZE        = 64;
  13.     const SOCKET_TERMINATE_BYTE         = "\0";
  14.    
  15.     const ERROR_SERVER_SETUP_MESSAGE    = "Could not setup server socket";
  16.     const ERROR_SERVER_SETUP_CODE       = 2;
  17.    
  18.     protected $_sAddress                = '127.0.0.1';
  19.     protected $_sPort                   = '23540';
  20.     protected $_rgClients               = array();
  21.     protected $_rgErrors                = array();
  22.     private   $__rgCache                = array();
  23.     private   $__rSocket                = null;
  24.    
  25.     public function __construct($sHost=null, $sPort=null)
  26.     {
  27.         if(isset($sHost)&&isset($sPort))
  28.         {          
  29.             $this->_sAddress= $sHost;
  30.             $this->_sPort   = $sPort;
  31.         }
  32.     }
  33.    
  34.     public function runServer()
  35.     {
  36.         if(!$this->__setup_socket())
  37.         {
  38.             $this->setError(self::ERROR_SERVER_SETUP_CODE, self::ERROR_SERVER_SETUP_MESSAGE);
  39.             return false;
  40.         }
  41.         while(true)
  42.         {
  43.             $this->_check_clients();
  44.             $this->_listen_clients();
  45.         }
  46.     }
  47.     //errors functions:
  48.     public function getLastError()
  49.     {
  50.         return $this->_rgErrors[count($this->_rgErrors)-1];
  51.     }
  52.    
  53.     public function setError($iCode, $sMessage)
  54.     {
  55.         $this->_rgErrors[]  = array($iCode=>$sMessage);
  56.     }
  57.     //cache functions:
  58.     public function getKey($mClient, $mKey)
  59.     {
  60.         $sKey   = $this->__generate_key_hash($mClient, $mKey);
  61.         return array_key_exists($sKey, $this->__rgCache)?$this->__rgCache[$sKey]:null;
  62.     }
  63.  
  64.     public function setKey($mClient, $mKey, $mValue)
  65.     {
  66.         if(!isset($mValue))
  67.         {
  68.             unset($this->__rgCache[$this->__generate_key_hash($mClient, $mKey)]);
  69.         }
  70.         else
  71.         {
  72.             $this->__rgCache[$this->__generate_key_hash($mClient, $mKey)]=$mValue;
  73.         }
  74.     }
  75.     //clients functions:
  76.     protected function _check_clients()
  77.     {
  78.         if(($rNewc = @socket_accept($this->__rSocket)) !== false)
  79.         {
  80.             socket_set_nonblock($rNewc);
  81.             $this->_rgClients[] = $rNewc;
  82.         }
  83.     }
  84.    
  85.     protected function _listen_clients($bCheckAlive=false)
  86.     {
  87.         foreach($this->_rgClients as $iIndex => $rClient)
  88.         {
  89.             if($sData = $this->__get_socket_data($rClient))
  90.             {
  91.                 if($rgCommand = $this->__parse_raw_command($sData))
  92.                 {
  93.                     $this->_execute_command($iIndex, $rgCommand[self::PARSER_RAW_SECTION_COMMAND], $rgCommand[self::PARSER_RAW_SECTION_DATA]);
  94.                 }
  95.             }
  96.         }
  97.     }
  98.     //command handle functions:
  99.     protected function _execute_command($mClient, $sCommand, $mParameters)
  100.     {
  101.         //need to use prefix, so call will be more safe:
  102.         if(method_exists($this, $sCommand=self::HANDLER_COMMAND_COMMON_PREFIX.$sCommand))
  103.         {
  104.             $this->$sCommand($mClient, $mParameters);
  105.         }
  106.     }
  107.    
  108.     protected function _hook_get($mClient, $mParameters)
  109.     {
  110.         $mClient    = is_resource($mClient)?$mClient:$this->_rgClients[$mClient];
  111.         $this->__send_socket_data($mClient, $this->getKey($mClient, (string)$mParameters));
  112.     }
  113.    
  114.     protected function _hook_set($mClient, $mParameters)
  115.     {
  116.         $mClient    = is_resource($mClient)?$mClient:$this->_rgClients[$mClient];
  117.         if($rgParameters = @unserialize($mParameters))
  118.         {
  119.             if(array_key_exists(self::HANDLER_COMMAND_SET_KEY, $rgParameters))
  120.             {
  121.                 $sKey = $rgParameters[self::HANDLER_COMMAND_SET_KEY];
  122.                 $this->setKey($mClient, $sKey, null);
  123.                 if(array_key_exists(self::HANDLER_COMMAND_SET_DATA, $rgParameters))
  124.                 {
  125.                     $this->setKey($mClient, $sKey, $rgParameters[self::HANDLER_COMMAND_SET_DATA]);                    
  126.                 }
  127.                 $this->__send_socket_data($mClient, self::HANDLER_COMMAND_SET_SUCCESS);
  128.                 return true;
  129.             }
  130.         }
  131.         $this->__send_socket_data($mClient, self::HANDLER_COMMAND_SET_FAILURE);
  132.         return false;
  133.     }
  134.    
  135.     private function __generate_key_hash($mClient, $mKey)
  136.     {
  137.         return md5($mClient."\n\n".$mKey);
  138.     }
  139.     //socket functions:
  140.     private function __setup_socket()
  141.     {
  142.         $this->__rSocket    = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  143.         if(!@socket_bind($this->__rSocket,$this->_sAddress,$this->_sPort))
  144.         {
  145.             unset($this->__rSocket);
  146.             return false;
  147.         }
  148.         socket_listen($this->__rSocket);
  149.         socket_set_nonblock($this->__rSocket);
  150.         return true;
  151.     }
  152.    
  153.     private function __send_socket_data($rSocket, $sData)
  154.     {
  155.         return socket_write($rSocket, $sData.self::SOCKET_TERMINATE_BYTE);
  156.     }
  157.    
  158.     private function __get_socket_data($rSocket)
  159.     {
  160.         $sResult = false;
  161.         while($sBuffer = @socket_read($rSocket, self::SOCKET_BLOCK_READ_SIZE))
  162.         {
  163.             $sResult.=$sBuffer;
  164.         }
  165.         return $sResult===false?null:$sResult;
  166.     }
  167.    
  168.     private function __parse_raw_command($sData)
  169.     {
  170.         $mData  = @unserialize($sData);
  171.         if(is_array($mData) && array_key_exists(self::PARSER_RAW_SECTION_COMMAND, $mData))
  172.         {
  173.             return $mData;
  174.         }
  175.         return null;
  176.     }
  177. }

и, собственно, пример использования:
PHP:
скопировать код в буфер обмена
  1. $rServer = new Cache_Server();
  2. $rServer->runServer();

- на этом функции сервера завершаются. То есть он не делает ничего "активного", лишь являясь хранилищем данных и принимая запросы на их изменение/предоставление.
Теперь клиент. Здесь тоже все предельно ясно - реализован синглтон, который пытается соединиться с сервером и умеющий работать с ним по предопределенному протоколу. Этот синглтон не закрывает сокет каждый раз при обращении, что экономит сетевой оверхед. Это может быть важной деталью - если использующий клиента скрипт не предполагает поддерживаемых соединений, то, вероятно, такой подход не подойдет. Правда, это легко исправимо. Код клиента:
PHP:
скопировать код в буфер обмена
  1. class Cache_Client
  2. {
  3.     const PARSER_RAW_SECTION_COMMAND    = 'raw_command';
  4.     const PARSER_RAW_SECTION_DATA       = 'raw_data';
  5.    
  6.     const COMMAND_GET                   = 'get';
  7.     const COMMAND_SET                   = 'set';
  8.     const COMMAND_SET_KEY               = 'key';
  9.     const COMMAND_SET_DATA              = 'data';
  10.    
  11.     const SOCKET_TERMINATE_BYTE         = "\0";
  12.    
  13.     const ERROR_CLIENT_SETUP_MESSAGE    = "Could not setup client socket";
  14.     const ERROR_CLIENT_SETUP_CODE       = 1;
  15.    
  16.     protected $_sAddress                = '127.0.0.1';
  17.     protected $_sPort                   = '23540';
  18.     protected $__rSocket                = null;
  19.     protected $_rgErrors                = array();
  20.    
  21.     protected static $_rInstance        = null;
  22.    
  23.     private function __construct()
  24.     {
  25.        
  26.     }
  27.    
  28.     public function setServerAddress($sAddress, $sPort)
  29.     {
  30.         $this->_sAddress    = $sAddress;
  31.         $this->_sPort       = $sPort;
  32.         $this->__setup_socket();
  33.         return $this;
  34.     }
  35.    
  36.     public static function getInstance()
  37.     {
  38.         if(isset(self::$_rInstance))
  39.         {
  40.             return self::$_rInstance;
  41.         }
  42.         self::$_rInstance = new Cache_Client;
  43.         self::$_rInstance->__setup_socket();
  44.         return self::$_rInstance;
  45.     }
  46.    
  47.     public function getLastError()
  48.     {
  49.         return $this->_rgErrors[count($this->_rgErrors)-1];
  50.     }
  51.    
  52.     public function setError($iCode, $sMessage)
  53.     {
  54.         $this->_rgErrors[]  = array($iCode=>$sMessage);
  55.     }
  56.    
  57.     public function getKey($sKey)
  58.     {
  59.         $this->__send_socket_data($this->__rSocket, serialize(
  60.                 array(
  61.                     self::PARSER_RAW_SECTION_COMMAND=> self::COMMAND_GET,
  62.                     self::PARSER_RAW_SECTION_DATA   => $sKey
  63.                 )
  64.         ));
  65.         if($sData = @unserialize($this->__get_socket_data($this->__rSocket)))
  66.         {
  67.             return $sData;
  68.         }
  69.         return null;
  70.     }
  71.    
  72.     public function setKey($sKey, $mValue)
  73.     {
  74.         $this->__send_socket_data($this->__rSocket, serialize(
  75.                 array(
  76.                     self::PARSER_RAW_SECTION_COMMAND=> self::COMMAND_SET,
  77.                     self::PARSER_RAW_SECTION_DATA   => serialize(array(
  78.                         self::COMMAND_SET_KEY   => $sKey,
  79.                         self::COMMAND_SET_DATA  => serialize($mValue)
  80.                     ))
  81.                 )
  82.         ));
  83.         return (bool)$this->__get_socket_data($this->__rSocket);
  84.     }
  85.    
  86.     public function unsetKey($sKey)
  87.     {
  88.         $this->__send_socket_data($this->__rSocket, serialize(
  89.                 array(
  90.                     self::PARSER_RAW_SECTION_COMMAND=> self::COMMAND_SET,
  91.                     self::PARSER_RAW_SECTION_DATA   => serialize(array(
  92.                         self::COMMAND_SET_KEY   => $sKey
  93.                     ))
  94.                 )
  95.         ));
  96.         return (bool)$this->__get_socket_data($this->__rSocket);
  97.     }
  98.    
  99.     private function __setup_socket()
  100.     {
  101.         $this->__rSocket    = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  102.         if(!@socket_connect($this->__rSocket, $this->_sAddress, $this->_sPort))
  103.         {
  104.             unset($this->__rSocket);
  105.             $this->setError(self::ERROR_CLIENT_SETUP_CODE, self::ERROR_CLIENT_SETUP_MESSAGE);
  106.             return false;
  107.         }
  108.         return true;
  109.     }
  110.    
  111.     private function __send_socket_data($rSocket, $sData)
  112.     {
  113.         if(!$rSocket)
  114.         {
  115.             return null;
  116.         }
  117.         return socket_write($rSocket, $sData);
  118.     }
  119.    
  120.     private function __get_socket_data($rSocket)
  121.     {
  122.         if(!$rSocket)
  123.         {
  124.             return null;
  125.         }
  126.         $sResult = false;
  127.         while(($sBuffer = @socket_read($rSocket, 1))!=self::SOCKET_TERMINATE_BYTE)
  128.         {
  129.             $sResult.=$sBuffer;
  130.         }
  131.         return $sResult===false?null:$sResult;
  132.     }
  133. }

и, опять же, пример использования:
PHP:
скопировать код в буфер обмена
  1. $rCache = Cache_Client::getInstance()->setServerAddress('127.0.0.1', '23540');
  2. var_dump($rCache->setKey('test', array(1,'foo', false)));
  3. var_dump($rCache->getKey('test'));
  4.  
  5. $rCacheIns = Cache_Client::getInstance();
  6.  
  7. var_dump($rCacheIns->unsetKey('test'));
  8. var_dump($rCacheIns->getKey('test'));

Пару слов о протоколе. Как это нетрудно заметить, данные, которые шлются между клиентом и сервером - обычный текст. Поэтому на помощь приходит функция serialize. Сериализуется команда, которая отправляется серверу, её параметры, а так же значение ключа, если оно передается. Клиент, соответственно, десериализует ответ при получении данных из кеша, а прочие же строки сервер отдает как есть (например,статус успешности операции установки ключа).


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
dubasua
Отправлено: 21 Февраля, 2013 - 16:26:32
Post Id



Посетитель


Покинул форум
Сообщений всего: 455
Дата рег-ции: Апр. 2012  


Помог: 7 раз(а)




EuGen пишет:
Код сервера:

Я так понял он запускается единожды? Допустим после старта самого сервера? И он не пускается с пользовательских скриптов.
А ему нужны какие нибудь права супер пользователя, я к тому что его реально запустить на недорогом покупном хостинге?
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 16:36:10
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Запускается 1 раз. Никаких прав не нужно, единственное, что нужно - это установленное расширение сокетов для PHP (но не уверен, что можно отыскать хостинг без него).
Но этот код - хоть и рабочий, все же является лишь прототипом, поскольку по-хорошему нужно делать обработку ошибок, сброс кеша на диск в случае непредвиденной остановки и т.п.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
dubasua
Отправлено: 21 Февраля, 2013 - 16:46:16
Post Id



Посетитель


Покинул форум
Сообщений всего: 455
Дата рег-ции: Апр. 2012  


Помог: 7 раз(а)




Ну таки не плохо, но все же, я пока что не увидел разницы над тем что предложил DeepVarvar.
 
 Top
DeepVarvar Супермодератор
Отправлено: 21 Февраля, 2013 - 16:47:46
Post Id



Активный участник


Покинул форум
Сообщений всего: 10421
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




Хе-хе, интересная игрушка Закатив глазки
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 16:48:06
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Разница в том, что во-первых, ресурс полностью разделяемый (блокировки отсутствуют в принципе, так как каждый клиент имеет свой кеш), и во-вторых, не требует специфичного shm-расширения (а вот оно-то как раз, не так часто бывает).


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
DeepVarvar Супермодератор
Отправлено: 21 Февраля, 2013 - 16:48:48
Post Id



Активный участник


Покинул форум
Сообщений всего: 10421
Дата рег-ции: Дек. 2008  
Откуда: Альфа Центавра


Помог: 353 раз(а)




dubasua пишет:
я пока что не увидел разницы над тем что предложил DeepVarvar.
EuGen сделал "копию" мемкеша, а я предложил хранить в оперативке напрямую без стороннего "сервера".
(Добавление)
Ну не суть. Суть в том какие задачи у dubasua Закатив глазки
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 16:54:51
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




DeepVarvar пишет:
а я предложил хранить в оперативке напрямую без стороннего "сервера".

Это, кстати, порождает еще одно отличие - клиент может иметь намного меньше потребляемой памяти по сравнению с сервером (поскольку клиент может вообще не хранить данные, а только работать с ними, таким образом, количество памяти, требуемой клиенту, ограничится лишь размером, требуемым для обработки конкретного ключа (или набора ключей) из кеша)
Копия memcached - звучит громко, хотя бы потому, что все это написано на PHP. Но суть - да, та же.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
dubasua
Отправлено: 21 Февраля, 2013 - 16:55:00
Post Id



Посетитель


Покинул форум
Сообщений всего: 455
Дата рег-ции: Апр. 2012  


Помог: 7 раз(а)




Хм,хм. Это к примеру если на одном хосте будут работать две одинаковые CMS, на которых работает пример DeepVarvar, то могут возникнуть парадоксы? А если будет пример EuGen, то кеш будет изолирован от каждой CMS?
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 16:56:56
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




В случае с кешем, который привел в пример я, кеш-сервер вообще ничего не знает о том, кто его использует. Это могут быть CMS или CLI-скрипты или вообще даже не PHP-скрипты - разницы нет, лишь бы соблюдали протокол работы с сервером.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
dubasua
Отправлено: 21 Февраля, 2013 - 17:02:27
Post Id



Посетитель


Покинул форум
Сообщений всего: 455
Дата рег-ции: Апр. 2012  


Помог: 7 раз(а)




EuGen пишет:
клиент может иметь намного меньше потребляемой памяти по сравнению с сервером
,
Я вот только начал въезжать А?!, клиент это мой хостинг, а сервер может быть совсем в другом месте(физически) на другом айпи???
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 17:04:11
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Именно так. Можете даже через WAN данные передавать. Правда, остается только посочувствовать той системе, быстродействие которой будет "улучшаться" подобным образом, поскольку скорость работы станет напрямую зависима от скорости передачи по сети и её надёжности.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
dubasua
Отправлено: 21 Февраля, 2013 - 17:09:11
Post Id



Посетитель


Покинул форум
Сообщений всего: 455
Дата рег-ции: Апр. 2012  


Помог: 7 раз(а)




Дык родилась идея создать платный сервис!!! покупаем VPS и кешируем половину ru-нета Улыбка
(Добавление)
Тем более половина готового кода уже есть! ;)
 
 Top
EuGen Администратор
Отправлено: 21 Февраля, 2013 - 17:47:03
Post Id


Профессионал


Покинул форум
Сообщений всего: 9098
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




На трафике разоритесь. Кешировать половину рунета можно и в memcached. Никакой Америки здесь не открыто.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
Shyt
Отправлено: 05 Января, 2014 - 14:46:12
Post Id


Новичок


Покинул форум
Сообщений всего: 2
Дата рег-ции: Янв. 2014  


Помог: 0 раз(а)




p.s Если что не судите строго, первый раз вообще смотрю на это

так всё интересно, но я много чего не смог понять, не могли бы вы мне помочь разобраться в этом примере и посмотреть как я разобрался в нем, я прогнал всё что понял но не уверен конечно что прав и остались некоторые нюансы

PHP:
скопировать код в буфер обмена
  1.  
  2. // стадия 1
  3. class Cache_Server{
  4.         // 2.0 обрабатываються все переменные
  5.     const PARSER_RAW_SECTION_COMMAND    = 'raw_command';
  6.     const PARSER_RAW_SECTION_DATA       = 'raw_data';
  7.     const HANDLER_COMMAND_COMMON_PREFIX = '_hook_';
  8.     const HANDLER_COMMAND_SET_KEY       = 'key';
  9.     const HANDLER_COMMAND_SET_DATA      = 'data';
  10.     const HANDLER_COMMAND_SET_SUCCESS   = 1;
  11.     const HANDLER_COMMAND_SET_FAILURE   = 0;
  12.        
  13.     const SOCKET_BLOCK_READ_SIZE        = 64;
  14.     const SOCKET_TERMINATE_BYTE         = "\0";
  15.        
  16.     const ERROR_SERVER_SETUP_MESSAGE    = "Could not setup server socket";
  17.     const ERROR_SERVER_SETUP_CODE       = 2;
  18.        
  19.     protected $_sAddress                = '127.0.0.1';
  20.         protected $_sPort                   = '23540';
  21.     protected $_rgClients               = array();
  22.     protected $_rgErrors                = array();
  23.     private   $__rgCache                = array();
  24.     private   $__rSocket                = null;
  25.    
  26.         // 2.1 запускается автоматом конструктор и выполняется внос данных в переменные
  27.     public function __construct($sHost=null, $sPort=null){
  28.         if(isset($sHost)&&isset($sPort)){          
  29.             $this->_sAddress = $sHost;
  30.             $this->_sPort = $sPort;
  31.                         }
  32.         }
  33.        
  34.         // вот наша стадия 2.2
  35.     public function runServer(){
  36.                 //3. как понимаю сначало это, на проверку создания
  37.         if(!$this->__setup_socket()){
  38.             $this->setError(self::ERROR_SERVER_SETUP_CODE, self::ERROR_SERVER_SETUP_MESSAGE);// 4.1 это вроде типа если ошибки
  39.             return false;
  40.                         }
  41.         //4.2 это вроде цикла прослушивания  
  42.                 while(true){
  43.             $this->_check_clients();
  44.             $this->_listen_clients();
  45.             }
  46.         }
  47.                
  48.         //errors functions:
  49.     public function getLastError(){
  50.         return $this->_rgErrors[count($this->_rgErrors)-1];
  51.         }
  52.      
  53.         // стадия 4.1
  54.     public function setError($iCode, $sMessage){
  55.         $this->_rgErrors[] = array($iCode=>$sMessage);// занос в массив
  56.         }
  57.                
  58.                
  59.     // ненашел?
  60.         public function getKey($mClient, $mKey){
  61.         $sKey = $this->__generate_key_hash($mClient, $mKey);
  62.         return array_key_exists($sKey, $this->__rgCache)?$this->__rgCache[$sKey]:null;
  63.         }
  64.    
  65.         // ненашел?
  66.     public function setKey($mClient, $mKey, $mValue){
  67.         if(!isset($mValue)){
  68.             unset($this->__rgCache[$this->__generate_key_hash($mClient, $mKey)]);
  69.         }else{
  70.             $this->__rgCache[$this->__generate_key_hash($mClient, $mKey)]=$mValue;
  71.             }
  72.         }
  73.  
  74.                
  75.         //8. бесконечный цикл порверки данных
  76.     protected function _check_clients(){
  77.                 // ждем данных но только не от себя
  78.         if(($rNewc = @socket_accept($this->__rSocket)) !== false){
  79.             socket_set_nonblock($rNewc); // это типа вроде мы, но я не допер
  80.             $this->_rgClients[] = $rNewc; // не понял зачем себя вносить в массив?
  81.             }
  82.         }
  83.    
  84.         //9. работа с клиентами
  85.     protected function _listen_clients($bCheckAlive=false// не понял что значит?){
  86.         foreach($this->_rgClients as $iIndex => $rClient){ // тоже не догнал манипуляция с клиентами чтоли?
  87.             if($sData = $this->__get_socket_data($rClient)){ // 10. типа что то читаем или получаем
  88.                 if($rgCommand = $this->__parse_raw_command($sData)){ // 11. ну это вроде обработка чего получили
  89.                     $this->_execute_command($iIndex, $rgCommand[self::PARSER_RAW_SECTION_COMMAND], $rgCommand[self::PARSER_RAW_SECTION_DATA]);// 12. что то о безопастности
  90.                     }
  91.                 }
  92.             }
  93.         }
  94.                
  95.                
  96.     // стадия 12
  97.     protected function _execute_command($mClient, $sCommand, $mParameters){
  98.         if(method_exists($this, $sCommand=self::HANDLER_COMMAND_COMMON_PREFIX.$sCommand)){
  99.             $this->$sCommand($mClient, $mParameters);
  100.             }
  101.         }
  102.        
  103.         // ненашел?
  104.     protected function _hook_get($mClient, $mParameters){
  105.         $mClient  = is_resource($mClient)?$mClient:$this->_rgClients[$mClient];
  106.         $this->__send_socket_data($mClient, $this->getKey($mClient, (string)$mParameters));
  107.         }
  108.      
  109.         // ненашел?
  110.     protected function _hook_set($mClient, $mParameters){
  111.         $mClient = is_resource($mClient)?$mClient:$this->_rgClients[$mClient];
  112.         if($rgParameters = @unserialize($mParameters)){
  113.             if(array_key_exists(self::HANDLER_COMMAND_SET_KEY, $rgParameters)){
  114.                 $sKey = $rgParameters[self::HANDLER_COMMAND_SET_KEY];
  115.                 $this->setKey($mClient, $sKey, null);
  116.                 if(array_key_exists(self::HANDLER_COMMAND_SET_DATA, $rgParameters)){
  117.                     $this->setKey($mClient, $sKey, $rgParameters[self::HANDLER_COMMAND_SET_DATA]);                    
  118.                     }
  119.                 $this->__send_socket_data($mClient, self::HANDLER_COMMAND_SET_SUCCESS);
  120.                                 return true;
  121.                                 }
  122.                         }
  123.             $this->__send_socket_data($mClient, self::HANDLER_COMMAND_SET_FAILURE);
  124.             return false;
  125.         }
  126.        
  127.         // ненашел?
  128.     private function __generate_key_hash($mClient, $mKey){
  129.         return md5($mClient."\n\n".$mKey);
  130.         }
  131.                
  132.     //5. подготовка к подключению и создания сокета
  133.     private function __setup_socket(){
  134.         $this->__rSocket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
  135.         if(!@socket_bind($this->__rSocket,$this->_sAddress,$this->_sPort)){
  136.             unset($this->__rSocket);
  137.             return false;
  138.             }
  139.        
  140.                 socket_listen($this->__rSocket);// 6. прослушиваем подключение
  141.         socket_set_nonblock($this->__rSocket);// 7. не врубился но вроде постояная активность
  142.         return true;
  143.         }
  144.    
  145.         // ненашел?
  146.     private function __send_socket_data($rSocket, $sData){
  147.         return socket_write($rSocket, $sData.self::SOCKET_TERMINATE_BYTE);
  148.         }
  149.    
  150.         // стадия 10
  151.     private function __get_socket_data($rSocket){
  152.         $sResult = false;
  153.         while($sBuffer = @socket_read($rSocket, self::SOCKET_BLOCK_READ_SIZE)){ // типа вносим в буфер по каким то определенным критериям
  154.             $sResult.=$sBuffer;
  155.             }
  156.         return $sResult===false?null:$sResult;
  157.         }
  158.                
  159.     // стадия 11  
  160.     private function __parse_raw_command($sData){
  161.         $mData = @unserialize($sData);
  162.         if(is_array($mData) && array_key_exists(self::PARSER_RAW_SECTION_COMMAND, $mData)){
  163.             return $mData;
  164.             }
  165.         return null;
  166.         }
  167.     }
  168.        
  169. $rServer = new Cache_Server();// 1. создаем класс
  170. $rServer->runServer();// 2.2 запускаем функцию
 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 1 (гостей: 1, зарегистрированных: 0)
« Пользовательские функции »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB