В материале о websocket мы рассмотрели построение вебсокет-клиента на JavaScript. В качестве Websocket-сервера использовался сторонний эхо-сервер. Для создания собственного WebSocket сервера, нам понадобиться решение на PHP или JavaScript (или на С++, Java, Scala и т.д.)
На работающей сборке OpenServer (можно использовать WAMP или др. сборку), создадим хост websocket.host
и перезапустим сборку для обновления файла hosts
(C:/Windows/System32/Drivers/etc/hosts
), чтобы в браузер «увидел» наш сайт.
Познакомимся с Ratchet, решением для организации работы с вебсокетами на PHP.
Создание WebSocket-сервера на Ratchet
Для установки Ratchet нам понадобиться установленный Composer. Если вы не знакомы с Composer
, срочно восполните этот пробел: перейдите по адресу https://getcomposer.org/download/, выполните команды начинающиеся с «php», а потом пропишите адрес к утилите в системной переменной PATH. Или скачайте composer.phar Создайте файл composer.json
внутри папки websocket.host
и заполните его зависимостями, как указано тут:
{ "autoload": { "psr-0": { "MyApp": "src" } }, "require": { "cboden/ratchet": "0.3.*" } }
После установки Composer
и описания файла .json
, нужно запустить установку Ratchet
через командную строку: php composer.phar install
В результате появится папка vendor
с необходимыми компонентами/библиотеками. Если интересно, можно посмотреть подробней об автозагрузке классов в PHP и работе с пространствами имён в PHP
В корне сайта создадим src/MyApp/Chat.php
:
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
public function onOpen(ConnectionInterface $conn) { }
public function onMessage(ConnectionInterface $from, $msg) { }
public function onClose(ConnectionInterface $conn) { }
public function onError(ConnectionInterface $conn, \Exception $e){ }
}
И в корне создадим chat-server.php
:
<?php
use Ratchet\Server\IoServer;
use MyApp\Chat;
require '/vendor/autoload.php';
$server = IoServer::factory(
new Chat(),
8080
);
$server->run();
Сам же чат обновим кодом:
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
// Store the new connection to send messages to later
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
, $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
// The sender is not the receiver, send to each client connected
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
// The connection is closed, remove it, as we can no longer send it messages
$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();
}
}
При запуске в консоли «php char-server.php» консоль будет «висеть» — сервер работает.
Остановим сервер Ctrl+C
и изменим файл сервера:
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
require '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
Настало время проверить работу. Поменяем адрес websocket сервера:
var socket = new WebSocket("ws://localhost:8080");
Запустим php char-server.php
и в форме внесём тестовые данные. В консольном окне мы должны увидеть приходящие сообщения. Если запустить вторую вкладку браузера, то станет возможным переписываться между двумя вкладками, одновременно видеть переписку в виде строк с JSON в консоли!
Чтобы сообщения накапливались подобно чату, нужно поменять строку в методе onmessage:
status.innerHTML += `пришли данные: <b>${message.name}</b>: ${message.msg}<br>`;
Если вы захотите сделать так, чтобы и отправитель тоже видел свои сообщения, нужно будет закомментировать фрагмент кода Chat.php:
foreach ($this->clients as $client) {
// if ($from !== $client) {
// Отправитель не является получателем, отправляем каждому подключенному клиенту
$client->send($msg);
// }
}
Поздравляю! У нас есть работающий Websocket Ratchet сервер!