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?