Сокеты сервера в PHP, мой опыт

В данной статья расскажу мой опыт работы с websockets в PHP. Сравним 2 пакеты который на мой взгляд являются лучшими.

Уже несколько дней как пробую создать сервер работающий в PHP а в частности в фреймворке Yii2.

Почему сокеты?

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

Какие пакеты пробовал использовать?

  • cboden/ratchet: “^0.4.0” – этот работает но не адаптирован под Yii2
  • workerman/phpsocket.io: “^1.1” – этот не понравился, поэтому даже не буду про него писать
  • yiicod/yii2-socketio: “^1.1” – не работает но по идее адаптирован

Работа с пакетом yiicod/yii2-socketio

Установил пакет через composer и настроил в файле config/console.php добавил такие конфигураций:

$config = [
    /* ... */
    'components' => [
         /* ... */
        'broadcastEvents' => [
            'class' => \yiicod\socketio\EventManager::class,
            'nsp' => 'unikalinyy cluchi',
            'namespaces' => [
                'app\socketio',
            ]
        ],
        'broadcastDriver' => [
            'class' => \yiicod\socketio\drivers\RedisDriver::class,
            'hostname' => 'localhost',
            'port' => 6379,
        ], 
    ],
    /* ... */
    'controllerMap' => [
        'socketio' => [
            'class' => \yiicod\socketio\commands\SocketIoCommand::class,
            'server' => 'localhost:6379'
        ],
    ]
    /* ... */
];

Потому что функция pcntl_fork не запускалась на сервера установленые на Windows (в моём случае это OpenServer + Windows 10) то пришлось взять в аренду выделеный сервер. Хотел купить от McHost потому что доволен ихними услугами, но у них слабые сервера не продаются (для тестов) поэтому взял за 150 руб в месяц сервер от компаний FirstVDS. Пришлось установить Redis и настроить прослушку портов.

После долгих попыток всё-же получилось и сервер включился.

Но после этого появилась новая проблема: когда клиент (браузер) отправлял запрос на подключение, ему отказывали в рукопожатие (handshake), поэтому пришлось пробовать другие пакеты.

Работа с пакетом cboden/ratchet

Установил себе данный пакет и вот что написал:

config/console.php

/*...*/
$config['bootstrap'][] = 'ratchet';
$config['modules']['ratchet'] = [
    'class' => 'app\controllers\AppController',
];

return $config;

servers/AppServer.php

<?php
namespace app\servers;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class AppServer implements MessageComponentInterface
{
    protected $clients;
    public function __construct()
    {
        $this->clients = new \SplObjectStorage; // Для хранения технической информации об присоединившихся клиентах используется технология SplObjectStorage, встроенная в PHP
    }

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);
        echo "New connection! ({$conn->resourceId})\n";
    }

    public function onMessage(ConnectionInterface $from, $msg)
    {
        echo $msg."\n";
        $from->send(strtoupper($msg));
    }

    public function onClose(ConnectionInterface $conn)
    {
        $this->clients->detach($conn);
        echo "Connection {$conn->resourceId} has disconnected\n";
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        echo "An error has occurred: {$e->getMessage()}\n";
        $conn->close();
    }
}

controllers/AppController.php

<?php

namespace app\controllers;

use app\servers\AppServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Server\IoServer;
use yii\web\Controller;

class AppController extends Controller
{

    public $io_port = 6380;

    /**
     * Start a Web Soket server
     * @return null
     */
    function setInstance() {
        $server = IoServer::factory(
            new HttpServer(
                new WsServer(
                    new AppServer()
                )
            ),
            $this->io_port
        );
        $server->run();
    }
}

Всё, это весь код и он работает. Работал и на локальной машине и работает и на VDS:

Заключение

Если есть рекомендаций можете оставить их в комментарии.
Данную статью писал пока ждал ответа от поддержки FirstVDS, не то чтоб они прямо очень трудно отвечают. Но ждать приходилось и больше получаса иногда, зато помогли – спасибо им.

Valeriu :

Посмотреть комментарии (2)

  • Очень разочаровался в работе серверов FirstVDS.

    Сайты неделю работали медленно очень, а потом день вообще не работали.

    Вернулся в McHost.