Tworze sobie serwer na socketach do pewnej gry, i mam problem z przechowywaniem informacji o klientach...
Napisałem sobie Event listener który odpala event w zależności od 1 pakietu w przychodzącej wiadomości. Wszystko odpala się OK i działa w porządku, jednak nie mam możliwości z gromadzeniem informacji o klientach połączonych do serwera. Próbuje użyć sesji, ale w każdym następnym kliencie się czyści lub się po prostu nie utworzyła. Próbowałem użyć Memcache i PDOSessionStorage.
Komenda która odpala serwer:
<?php /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('Server starting'); $communication = $this->getContainer()->get('uo_server.server_communication'); $pdo = new \PDO('mysql:host=127.0.01;dbname=uo-session', 'root', null); $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); $dbOptions = array( 'db_table' => 'sessions', 'db_id_col' => 'sess_id', 'db_data_col' => 'sess_data', 'db_time_col' => 'sess_time', 'db_lifetime_col' => 'sess_lifetime', 'lock_mode' => 0 ); $sessionProvider = new PdoSessionHandler($pdo, $dbOptions); $server = IoServer::factory( new SessionProvider($communication, $sessionProvider), 2593, '127.0.0.1'); $server->run(); }
Fragment Message component:
<?php function __construct(ContainerInterface $container) { $this->container = $container; $this->packetDispatcher = $container->get('uo_server.packets_event_dispatcher'); $this->connections = new ArrayCollection(); } /** * When a new connection is opened it will be passed to this method * @param ConnectionInterface $conn The socket/connection that just connected to your application * @throws \Exception */ function onOpen(ConnectionInterface $conn) { $this->connections->add($conn); /** * @var Session $session */ $session = $conn->Session; $session->setId('session_'.$conn->resourceId); $session->start(); } /** * This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed. * @param ConnectionInterface $conn The socket/connection that is closing/closed * @throws \Exception */ function onClose(ConnectionInterface $conn) { $conn->Session->save(); if($this->connections->contains($conn)) { $this->connections->removeElement($conn); } } /** * If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown, * the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method * @param ConnectionInterface $conn * @param \Exception $e * @throws \Exception */ function onError(ConnectionInterface $conn, \Exception $e) { $conn->Session->save(); // TODO: Implement onError() method. } /** * Triggered when a client sends data through the socket * @param \Ratchet\ConnectionInterface $from The socket/connection that sent the message to your application * @param string $msg The message received * @throws \Exception */ function onMessage(ConnectionInterface $conn, $msg) { $this->packetDispatcher->dispatchEvent($conn, $msg); $conn->Session->save(); }
Funkcja dispatch-ująca event-y:
<?php public function dispatchEvent(ConnectionInterface $sender, $msg) { $data = unpack('C*',$msg); $eventPacket = "0x".DataConverter::convertDecimalToHex($data[1]); $event = isset($this->packetsEvents[$eventPacket]) ? $this->packetsEvents[$eventPacket] : null; if ($event !== null) { $incomingEvent = new MainEvent($sender, $msg); if ($this->dispatcher->hasListeners($event)) { $this->dispatcher->dispatch($event, $incomingEvent); } else { Logger::Log('Event :'.$event.' is not implement yet!'); } } }
No i przykładowy event logowania:
<?php public function onLogin(MainEvent $event) { $this->event = $event; $packetReader = new PacketReader($this->event->getMessage()); $login = $packetReader->getByteFrom(2, 30); $password = $packetReader->getByteFrom(32, 30); //todo some byte on the end? if($this->accountFinder->checkAccountAccess($login, $password)) { Logger::Log('try to log:'.$login . '/' . $password.';'); $account = $this->accountFinder->getAccount($login, $password); return $this->loginSuccess($account); } if($this->serverInfo['auto_account'] && $this->accountFinder->checkAccountExist($login) === false) { Logger::Log('account not found, but autoaccounting is on. Account created;'); $account = $this->accountFinder->createUser($login, $password); return $this->loginSuccess($account); } Logger::Log('login for credientals: '.$login.'/'.$password.' failure;'); $this->loginFailure($login); } private function loginSuccess(Account $account) { $ip = explode(".", $this->serverInfo['host']); $packet = new Packet; $packet ->prependPacket("A8") ->appendPacket("FF") ->appendPacket(DataConverter::convertDecimalToHex(1), 4) ->appendPacket(DataConverter::convertDecimalToHex(1), 4) ->appendPacket(DataConverter::convertStringToHex($this->serverInfo['name']), 64, Packet::PAD_FROM_RIGHT) ->appendPacket(DataConverter::convertDecimalToHex($this->serverInfo['full']), 2) //todo full is not from PARAM!!! ->appendPacket(DataConverter::convertDecimalToHex($this->serverInfo['timezone']), 2); for ($i=3; $i>=0; $i--) { $packet->appendPacket(DataConverter::convertDecimalToHex($ip[$i]), 2); } $currentLenght = $packet->getPacketSize(); $packet->injectPacket(DataConverter::convertDecimalToHex($currentLenght + 2), 4, 2); $this->event->setToSession('accountId', $account->getId()); $this->event->getClientSession()->save(); $this->event->getClient()->send($packet->getPacket()); return true; } /** * TODO FAILURE FROM BANS ETC. * @return bool */ private function loginFailure($login) { $reason = 0; if ($this->accountFinder->checkAccountExist($login)) { $reason = 3; } $packet = new Packet; $packet ->prependPacket("82") ->appendPacket(DataConverter::convertDecimalToHex($reason), 2); $this->event->getClient()->send($packet->getPacket()); return true; }
Kiedy próbuje zaczytać w następnym event-cie coś z sesji no to zwraca mi niestety NULL-a. Dumpując sobie sesje ewidentnie widać że ona nie istnieje. Tak samo w przypadku PDOSession nie dodaje się wpis do DB, także definitywnie coś tu nie działa. Czy ktoś może miał podobny problem i udało mu się go rozwiązać ? Chyba że istnieje jakiś inny sposób na przechowywanie danych o klientach?