Quantcast
Viewing all articles
Browse latest Browse all 21942

PHP Sockets - Przechowywanie w sesji (Symfony, Ratchet)

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?

 


Viewing all articles
Browse latest Browse all 21942