Веб сокеты php. Веб-сокеты. Примеры веб-сокетов в сети

  • 03.11.2019

Сатья посвещена сетевому програамированию, а в частности — программированию сокетов на PHP. Для сетевого взаимодействия в PHP существует две категории функций:

  1. Функция fsockopen(string hostname, integer port, integer error_number, string error_description, double timeout) — она открывает сетевое соединение как файловый поток и возвращает дискриптор файла с которым работают функции fputs, fgets и т.д.
  2. Функции которые передают информацию непосредственно на уровне IP-протокола. И это гораздо более низкий уровень по сравнению с уровнем на котором работает функция fsockopen.

Рассматриваться будут только функции под номером 2, т.к. они более интересны.
Для начала проверим, подключена ли у Вас библиотека работы с сокетами.

Проверить это можно следующим скриптом:

If(extension_loaded("sockets")) echo "расширение загружено"; else echo "расширение не загружено"; ?>

Если расширение не загружено, то Вам следует его загрузить.

И так. Наиболее простой в рамках статьи пример — echo-сервер. Эхо-сервер — это означает, что строка отправленная клиентом серверу, возвращается обратно. То есть сервер получает какое-то сообщение от клиента, что-то с ним делает и отправляет ему обратно.

У нас будет 2 скрипта:

  1. Сервер или демон (daemon).
  2. Клиент.

Скрипт «Клиент».

Для реализации клиента нам понадобятся следующие функции работающие с сокетами:

  1. socket_create (integer family, integer socket_type, integer protocol); — функция создаёт сокет и возвращает ресурс сокета. Первым аргументом является семейство протокола, Если соединение будет через Internet, то задаваемое значение должно быть — AF_INET; Если соединение будет происходить через сокеты UNIX — AF_UNIX; Вторым аргументом является тип сокета. Обычно используются SOCK_STREAM для TCP взаимодействия и SOCK_DGRAM для UPD взаимодействия. Третий аргумент задаёт протокол SOL_TCP или SOL_UPD в зависимости от типа.
  2. socket_connect (resource socket, string address, integer port); — после создания сокета необходимо к нему подключится. Первым аргументом является ресурс созданного сокета, вторым IP адрес сокета если семейство протокола AF_INET, или pathname сокета Unix-домена если сокет из семейства AF_UNIX. Третьем агрументом является номер порта с которым должно быть установлено соединение.
  3. socket_read (resource socket, integer length, integer type); — функция считывает заданное в аргументе lenght количество байт из указанного сокета. По умолчанию чтение производится без учета управляющих символов, или можно задать в аргументе type — PHP_BINARY_READ, для учета управляющих символов необходимо задать значение PHP_NORMAL_READ.
  4. socket_write (resource socket, string buffer, integer length); — функция записывает данные в сокет.
  5. socket_close (resource socket); — закрывает сокет и освобождает память.

Листинг 1.0 — Клиент

Set_time_limit(0); ob_implicit_flush(); echo "- Клиент

"; $address = "127.0.0.1"; // адресс localhost. $port = 5555; // порт с которым будет установленно соединение. echo "Создание сокета... "; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket "; } else { echo "OK
"; } echo "Подключение к сокету... "; $connect = socket_connect($socket, $address, $port); if($connect === false) { echo "Ошибка: ".socket_strerror(socket_last_error())."
"; } else { echo "OK

"; $msg = "Hello Сервер!"; echo "Говорим серверу \"".$msg."\"..."; socket_write($socket, $msg, strlen($msg)); echo "OK
"; echo "Сервер сказал: "; $awr = socket_read($socket, 1024); echo $awr."
"; $msg = "exit"; echo "Говорим серверу \"".$msg."\"..."; socket_write($socket, $msg, strlen($msg)); echo "OK
"; } if(isset($socket)) { echo "Закрываем соединение... "; socket_close($socket); echo "OK
"; } ?>

Скрипт «Сервер».

Для реализации сервера нам понадобятся следующие функции работающие с сокетами:

  1. Все те функции которые были описаны выше.
  2. socket_bind (resource socket, string address, integer port); — функция привязывает адрес к сокету. Аргумент addres — IP адрес сокета если семейство протокола AF_INET, или pathname сокета Unix-домена если сокет из семейства AF_UNIX.
  3. socket_listen (resource socket, integer backlog) — функция прослушивает входящие соединения в сокет. Необязательный второй аргумент устанавливает максимальный размер очереди запросов, ожидающих соединения.
  4. socket_accept (resource socket); — После того как сокет создан, привязан, и начал прослушивание, именно эта функция делает сервер сервером. Функция принимает входящие соединения.

Листинг 1.1 — Сервер

Set_time_limit(0); ob_implicit_flush(); echo "- Сервер

"; $address = "127.0.0.1"; $port = 5555; echo "Создание сокета... "; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if($socket "; } else { echo "OK
"; } echo "Привязывание сокета... "; $bind = socket_bind($socket, $address, $port); if($bind "; } else { echo "OK
"; } echo "Прослушивание сокета... "; $listen = socket_listen($socket, 5); if($listen "; } else { echo "OK
"; } while(true) { echo "Ожидаем... "; $accept = socket_accept($socket); if($accept "; break; } else { echo "OK
"; } $msg = "Hello, Клиент!"; echo "Отправить клиенту \"".$msg."\"... "; socket_write($accept, $msg, strlen($msg)); echo "OK
"; while(true) { $awr = socket_read($accept, 1024); if (false === $awr) { echo "Ошибка: ".socket_strerror(socket_last_error())."
"; break 2; } else { if (trim($awr) == "") break; else echo "Клиент сказал: ".$awr."
"; } if ($awr == "exit") { socket_close($accept); break 2; } echo "Сказать клиенту \"".$msg."\"... "; socket_write($accept, $awr, strlen($awr)); echo "OK
"; } } if (isset($socket)) { echo "Закрываем соединение... "; socket_close($socket); echo "OK
"; } ?>

Вот собственно и всё. Вначале запустите скрипт сервер, он создаст, привяжет, начнёт прослушивание сокета и установится в режим ожидания клиента. Далее запустите клиента.

Так же хочу отметить что наиболее полезной является функция:
socket_select (array read, array write, array except, integer timeout_seconds, integer timeout_microseconds); — Функция контролирует изменения происходящие на узлах. PHP просматривает поступления новых дынных на сокетах, заданных в массиве read. PHP просматривает готовность к приёму данных на сокетах, заданных в массиве write. PHP просматривает на наличие ошибок потоки, заданные в аргументе except. В таймаутах задается время, по истечению которого функция будет возвращать кол-во сокетов изменивших своё состояние или FALSE.

Эта функция не заменима для мониторинга клиентов висящих на сокете.

В статье приведена малая часть всех функций работающих сокетами, кого заинтересовало, откапывайте мануалы, читайте… Удачных экспериментов…

В предыдущей статье я рассказывал про . Мы с Вами с использованием сокетов создали сервер на PHP . А в этой статье мы с Вами напишем клиента на PHP , который будет отправлять запрос на сервер и получать от него ответ.

Привожу код клиента на PHP :

header("Content-Type: text/plain;"); //Мы будем выводить простой текст
set_time_limit(0); //Скрипт должен работать постоянно
ob_implicit_flush(); //Все echo должны сразу же выводиться
$address = "localhost"; //Адрес работы сервера
$port = 1985; //Порт работы сервера (лучше какой-нибудь редкоиспользуемый)
if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) < 0) {
//AF_INET - семейство протоколов
//SOCK_STREAM - тип сокета
//SOL_TCP - протокол
echo "Ошибка создания сокета";
}
else {
echo "Сокет создан\n";
}
$result = socket_connect($socket, $address, $port);
if ($result === false) {
echo "Ошибка при подключении к сокету";
} else {
echo "Подключение к сокету прошло успешно\n";
}

echo "Сообщение от сервера: $out.\n";
$msg = "15";

socket_write($socket, $msg, strlen($msg)); //Отправляем серверу сообщение
$out = socket_read($socket, 1024); //Читаем сообщение от сервера
echo "Сообщение от сервера: $out.\n"; //Выводим сообщение от сервера
$msg = "exit"; //Команда отключения
echo "Сообщение серверу: $msg\n";
socket_write($socket, $msg, strlen($msg));
echo "Соединение завершено\n";
//Останавливаем работу с сокетом
if (isset($socket)) {
socket_close($socket);
echo "Сокет успешно закрыт";
}
?>

Код хорошо прокомментирован, поэтому, думаю, что здесь всё предельно понятно. Алгоритм работы клиента тривиальный: создание сокета, подключение к серверу, отправка запросов, получение ответов, закрытие соединения. Мы с Вами отправили число 15 . Если Вы читали предыдущую статью, то помните, что задача сервера это число возвести в квадрат и вернуть его. Поэтому если Вы запустите этот клиент, то увидите от сервера 225 (15*15 ). Потом мы подаём команду shutdown , которая останавливает сервер.

Теперь у Вас есть минимальный набор знаний по работе с сокетами, а вообще тема очень интересная, поэтому Вы можете изучить её более детально. Вы можете создавать очень сложные клиент-серверные приложения, к котором Вы всегда сможете подключиться и отправлять самые различные запросы, которые сервер будет обрабатывать.

Веб-сокеты

Серверные события, рассмотренные ранее, являются идеальным инструментом, когда требуется получить последовательность сообщений с веб-сервера. Но при этом связь получается полностью односторонней. Браузер не может отвечать на сообщения или вступать в более сложный диалог с сервером.

Если вы создаете веб-приложение, в котором требуется серьезное двустороннее взаимодействие браузера с веб-сервером, лучшим подходом к его реализации (не прибегая к помощи Flash) будет, возможно, использование объекта XMLHttpRequest. В зависимости от типа создаваемого приложения этот подход может работать так, как требуется. Но здесь существует и достаточное количество возможных проблем.

Прежде всего, объект XMLHttpRequest не очень хорошо подходит для быстрого обмена множественными сообщениями (например, в чате). Потом, в нем нет возможности связать один вызов с другим, поэтому при каждом новом запросе от веб-страницы сервер должен вычислять с самого начала, кому эта страница принадлежит. Поэтому уровень сложности кода для обработки ряда связанных запросов от веб-страницы может очень быстро вырасти до практически нереализуемой.

Для всех этих проблем есть решение, хотя оно еще не вполне готово. Этим решением является технология веб-сокетов (web sockets) , которая позволяет браузеру удерживать открытое подключение к серверу и обмениваться сообщениями в течение любого требуемого времени.

Технология веб-сокетов вызвала большое возбуждение в среде веб-разработчиков, но она еще находится в процессе развития, хотя уже имеет неплохую браузерную совместимость:

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

Получение доступа к веб-сокетам

Веб-сокеты являются специализированным инструментом. Они актуальны для таких приложений, как чат, массивные многопользовательские игры или инструмент для пирингового взаимодействия. Веб-сокеты позволяют создавать новые типы приложений, но применять их в большинстве современных веб-приложений, движимых JavaScript, скорее всего, не имеет смысла.

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

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

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

Чтобы дать вам представление о масштабе сервера веб-сокетов, рассмотрите некоторые из задач, которые сервер сокетов должен выполнять:

    составить "словарь" сообщений, иными словами, решить, какие типы сообщений являются допустимыми, а какие нет;

    выявлять ошибки при отправке сообщений клиентам и прекратить попытки связаться с ними, если кажется, что их больше не существует;

    обрабатывать все данные в оперативной памяти, т.е. данные, доступ к которым может потребоваться всем клиентам, и делать это надежно и безопасно. Здесь имеется обилие возможных неявных проблем, например, когда один клиент пытается присоединиться к обмену, в то время как другой отключается, а информация об обоих хранится в одном и том же объекте в памяти.

Разработчики, скорее всего, никогда не будут сами создавать серверную программу, использующую веб-сокеты, т.к. это просто-напросто не стоит требуемых для этого значительных усилий. Самым легким подходом в этой области будет установить чей-то другой сервер веб-сокетов и разрабатывать свои веб-страницы под него. Так как использование части JavaScript стандарта веб-сокетов не несет трудностей, это не должно доставлять каких-либо проблем.

Другим подходом будет взять чей-либо код сервера веб-сокетов и подогнать его под свои требования. В настоящее время существует великое множество проектов (многие из которых бесплатные и с открытым кодом), в которых разрабатываются серверы веб-сокетов для решения различных задач, на разных языках серверного программирования.

Простой клиент веб-сокетов

С точки зрения веб-страницы функциональность веб-сокетов легко понять и использовать. Первый шаг - это создать объект WebSocket и передать ему URL. Код для этого подобен следующему:

Var socket = new WebSocket("ws://localhost/socketServer.php");

Строка URL начинается с текста ws://, который идентифицирует подключение типа веб-сокет. Этот URL указывает файл веб-приложения на сервере (в данном случае это сценарий socketServer.php).

Стандарт веб-сокетов также поддерживает URL, которые начинаются с текста wss://, что указывает на требование использовать безопасное, зашифрованное подключение (точно так же, как и при запросе веб-страницы указывается URL, начинающийся с https:// вместо http://).

Веб-сокеты могут подключаться не только к своему веб-серверу. Веб-страница может открыть подключение к серверу веб-сокетов, исполняющемуся на другом веб-сервере, не требуя для этого никаких дополнительных усилий.

Само обстоятельство создания объекта WebSocket понуждает страницу пытаться подключиться к серверу. Дальше надо использовать одно из четырех событий объекта WebSocket: onOpen (при установлении подключения), onError (когда возникает ошибка), onClose (при закрытии подключения) и onMessage (когда страница получает сообщение от сервера):

Socket.onopen = connectionOpen; socket.onmessage = messageReceived; socket.onerror = errorOccurred; socket.onopen = connectionClosed;

Например, в случае успешного подключения неплохо бы отправить соответствующее подтверждающее сообщение. Такое сообщение доставляется с помощью метода send() объекта WebSocket, которому в качестве параметра передается обычный текст. Далее приведена функция, которая обрабатывает событие onopen и отправляет сообщение:

Function connectionOpen() { socket.send("UserName:[email protected]"); }

Предположительно, веб-сервер получит это сообщение и даст на него ответ.

События onError и onClose можно использовать для отправки извещений посетителю веб-страницы. Но безоговорочно самым важным является событие onMessage, которое срабатывает при получении новых данных от сервера. Опять же, код JavaScript для обработки этого события не представляет никаких сложностей - мы просто извлекаем текст сообщения из свойства data:

Function messageReceived(e) { messageLog.innerHTML += "

Если веб-страница решит, что вся ее работа выполнена, она может закрыть подключение, используя метод disconnect() :

Socket.disconnect();

Из этого обзора веб-сокетов можно видеть, что использование сервера веб-сокетов стороннего разработчика не представляет никаких трудностей - нам нужно лишь знать, какие сообщения отправлять, а какие - ожидать.

Чтобы заставить подключение веб-сокетов работать, выполняется большой объем работы за кулисами. Прежде всего, веб-страница устанавливает связь по обычному стандарту HTTP. Потом это подключение нужно повысить до подключения веб-сокетов, позволяющего свободную двустороннюю связь. На этом этапе возможны проблемы, если между компьютером клиента и веб-сервером находится прокси-сервер (как, например, в типичной корпоративной сети). Прокси-сервер может отказаться сотрудничать и разорвет подключение. Эту проблему можно решить, обнаруживая неудачное подключение (посредством события onError объекта WebSocket) и применяя один из заполнителей (polyfills) для сокетов, описанных на веб-сайте GitHub. Эти заполнители применяют метод опроса, чтобы эмулировать подключение веб-сокетов.

Примеры веб-сокетов в сети

Если вы заинтересованы опробовать веб-сокеты, в сети есть много сайтов, на которых можно запустить свою разработку.

Для начала попробуйте сайт websocket.org , который предоставляет простейший сервер веб-сокетов: веб-страница отправляет ему сообщение, а он возвращает это же сообщение веб-странице:

Хотя этот сервер веб-сокетов и не представляет ничего особенного, на нем вы можете испробовать все возможности объекта WebSocket. Более того, к этому серверу можно подключиться со страницы, расположенной как на промышленном веб-сервере, так и на тестовом веб-сервере на вашем компьютере, или даже со страницы, просто запускаемой с жесткого диска:

Var socket = new WebSocket("ws://echo.websocket.org"); socket.onopen = connectionOpen; socket.onmessage = messageReceived; function connectionOpen() { socket.send("UserName:[email protected]"); } function messageReceived(e) { var messageLog = document.getElementById("messageLog"); messageLog.innerHTML += "
" + "Ответ сервера: " + e.data; }

Существуют и серверы веб-сокетов, предоставляющие другие возможности, включая следующие.

В данной статье рассмотрим работу с библиотекой phpws , которая нужна для организации приложений или WEB — приложений на основе сокетов и запустим парочку стандартных примеров, которые представлены на странице репозитория GitHub данного проекта.

Примечание. Сокеты у нас будут работать, как на серверной части, так и на клиентской. На серверной части этим займется стандартный WebSocket, который появился в HTML5, а работу на серверной части, где у нас PHP будет выполнять библиотека phpws. Есть много подобных библиотек, пожалуй, особенно следует отметить Ratchet , который мне показался громоздким для моего маленького проекта и я остановился на phpws.

Нам нужен Composer

Очень удобная штука, которая облегчит всю работу с зависимостями и библиотеками, которые включены в проекты. По всеобщему стандарту кодирования или, проще говоря, по правильному написанию кода все библиотеки, пакеты, зависимости или проекты принято хранить в репозиториях исходных кодов, которые потом подключаются в проект за парочку команд через менеджеры пакетов или через менеджеры зависимостей. Для каждого языка есть свой менеджер или почти для каждого, поэтому, вооружимся данным инструментом и установим его в систему командой в Linux

$ curl -s https://getcomposer.org/installer | php

Мы его скачали, но команды composer не будут выполняться через PATH, поэтому переместим скачанное в /usr/local/bin

$ mv composer.phar /usr/local/bin/composer

Выполняем команду и получаем результат в виде инструкций и команд Composer, что говорит об удачной установке

$ composer

Для Windows и Mac можно посмотреть инструкцию на офф-сайте .

Примечание. Все зависимости, которые нужно подключать надо указывать в файле composer.json в корне проекта, который скачает, обновит и соберет все зависимости в одну папку vendor, из которого потом можно загружать через автозагрузчик классов. У Composer есть свое хранилище пакетов и библиотек и называется Packagist , который позволяет указывать vendor/package и он будет установлен. Да, можно указывать конкретные адреса svn/git репозиториев в composer.json, но это неудобно. Намного удобнее иметь какой-то центральный пункт, где есть соответствия пакетов с их адресами репозиториев. Это Packagist .

Нам нужна библиотека phpws

Для подключения к проекту, нам нужно зайти в корень папки проекта или в подпапку, если это будет частью проекта и там установить данную библиотеку, но сначала надо создать в этом месте composer.json, который выполним потом через консоль командами composer и он прочитав, все нам установит. Для этого создаем данный файл со следующим содержимым

{ "repositories": [ { "type": "vcs", "url": "https://github.com/Devristo/phpws" } ], "require": { "devristo/phpws": "dev-master" } }

В данном случае, мы указали, что скачивать прямо с репозитория GitHub без посредничества Packagist.

Выполним данный файл командой

$ composer install

После чего в папке появится подпапка vendor со скачанными библиотеками и нам остается их подключить и использовать.

Нам нужны базовые понимания работы WebSocket с PHP

И так, на минуточку разберемся, что делать со скачанными библиотеками и как их использовать, углубляться не буду, поэтому, если на пальцах, то нам нужно 2 файла:

  1. client.html — файл клиентской части, который видит тот, кто за браузером. В нем с сокетом работает JavaScript;
  2. server.php — собственно, наш сокет-сервер, который обрабатывает все запросы от клиента и отвечает ему обработанными обтветами.

Для соединения нам надо указать схему соединения или протокол связи, ip — адрес сервера. Если удаленный сервер, то надо указать ip — адрес хоста или VPS, а если локальный, то localhost, который равен адресу 127.0.0.0 и указываем еще порт, на котором служба сервера будет запущена под собственным PID. Все эти данные указываются при создании экземпляра соединения.

Для клиентской части:

Var socket = "ws://127.0.0.0:12345/";

Для серверной части:

$server = new WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger);

Стандартный пример вывода текущего времени сервера с обновлением до секунды

Для работы данного примера нужно единожды запустить файл server.php через консоль и после выполнения данного скрипта запуститься сокет-сервер со своим PID

Что делает пример? В примере показано, как до долей секунды сокет обновляет информацию времени на сервер и выдает его клиенту

Клиентская часть:

Timers

Server Time

Status:
Time:

Var socket = new WebSocket("ws://localhost:12345"); socket.onopen = function(msg){ document.getElementById("status").innerHTML = "Online"; }; socket.onclose = function(msg){ document.getElementById("status").innerHTML = "Offline"; } socket.onmessage = function(msg){ document.getElementById("time").innerHTML = msg.data; };

Серверная часть:

#!/php -q addWriter($writer); // Create a WebSocket server using SSL $server = new WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger); // Each 0.5 seconds sent the time to all connected clients $loop->addPeriodicTimer(0.5, function() use($server, $logger){ $time = new DateTime(); $string = $time->format("Y-m-d H:i:s"); $logger->notice("Broadcasting time to all clients: $string"); foreach($server->getConnections() as $client) $client->sendString($string); }); // Bind the server $server->bind(); // Start the event loop $loop->run();

Стандартный пример простого чата

Показан пример простого чата. Визуально он имеет вид, как на картинке

Клиентская часть:

WebSocket TEST

WebSocket Test

Server will echo your response!
var socket; function createSocket(host) { if ("WebSocket" in window) return new WebSocket(host); else if ("MozWebSocket" in window) return new MozWebSocket(host); throw new Error("No web socket support in browser!"); } function init() { var host = "ws://127.0.0.0:12345/chat"; try { socket = createSocket(host); log("WebSocket - status " + socket.readyState); socket.onopen = function(msg) { log("Welcome - status " + this.readyState); }; socket.onmessage = function(msg) { log(msg.data); }; socket.onclose = function(msg) { log("Disconnected - status " + this.readyState); }; } catch (ex) { log(ex); } document.getElementById("msg").focus(); } function send() { var msg = document.getElementById("msg").value; try { socket.send(msg); } catch (ex) { log(ex); } } function quit() { log("Goodbye!"); socket.close(); socket = null; } function log(msg) { document.getElementById("log").innerHTML += "
" + msg; } function onkey(event) { if (event.keyCode == 13) { send(); } }

Серверная часть:

#!/php -q php chat.php use Devristo\Phpws\Framing\WebSocketFrame; use Devristo\Phpws\Framing\WebSocketOpcode; use Devristo\Phpws\Messaging\WebSocketMessageInterface; use Devristo\Phpws\Protocol\WebSocketTransportInterface; use Devristo\Phpws\Server\IWebSocketServerObserver; use Devristo\Phpws\Server\UriHandler\WebSocketUriHandler; use Devristo\Phpws\Server\WebSocketServer; /** * This ChatHandler handler below will respond to all messages sent to /chat (e.g. ws://localhost:12345/chat) */ class ChatHandler extends WebSocketUriHandler { /** * Notify everyone when a user has joined the chat * * @param WebSocketTransportInterface $user */ public function onConnect(WebSocketTransportInterface $user){ foreach($this->getConnections() as $client){ $client->sendString("User {$user->getId()} joined the chat: "); } } /** * Broadcast messages sent by a user to everyone in the room * * @param WebSocketTransportInterface $user * @param WebSocketMessageInterface $msg */ public function onMessage(WebSocketTransportInterface $user, WebSocketMessageInterface $msg) { $this->logger->notice("Broadcasting " . strlen($msg->getData()) . " bytes"); foreach($this->getConnections() as $client){ $client->sendString("User {$user->getId()} said: ".$msg->getData()); } } } class ChatHandlerForUnroutedUrls extends WebSocketUriHandler { /** * This class deals with users who are not routed */ public function onConnect(WebSocketTransportInterface $user){ //do nothing $this->logger->notice("User {$user->getId()} did not join any room"); } public function onMessage(WebSocketTransportInterface $user, WebSocketMessageInterface $msg) { //do nothing $this->logger->notice("User {$user->getId()} is not in a room but tried to say: {$msg->getData()}"); } } $loop = \React\EventLoop\Factory::create(); // Create a logger which writes everything to the STDOUT $logger = new \Zend\Log\Logger(); $writer = new Zend\Log\Writer\Stream("php://output"); $logger->addWriter($writer); // Create a WebSocket server $server = new WebSocketServer("tcp://127.0.0.0:12345", $loop, $logger); // Create a router which transfers all /chat connections to the ChatHandler class $router = new \Devristo\Phpws\Server\UriHandler\ClientRouter($server, $logger); // route /chat url $router->addRoute("#^/chat$#i", new ChatHandler($logger)); // route unmatched urls durring this demo to avoid errors $router->addRoute("#^(.*)$#i", new ChatHandlerForUnroutedUrls($logger)); // Bind the server $server->bind(); // Start the event loop $loop->run();

Запускать данный пример, надо, как и предыдущий — единожды через консоль запускаем файл server.php и через браузер входим в клиентскую часть client.html, подключив скрипт script.js .

Работа с PHP — сокет сервером из консоли

Для того, чтобы обновлять код сервера и перезапускать очень удобно использовать команды для остановки и перезапуска файла сервера PHP через консоль иначе может происходить казусная ситуация, когда вроде бы правляешь код сервера, а он выполняет старый.

Сначала выводим PID процесса запущенного сокет-сервера. Его мы узнаем посмотрев список запущенных сокетов через их порты через команду:

Netstat --tcp --listening --program

Находя из списка нужный PID убиваем его через команду:

Kill %pid%

Идеально, если закроем WebSocket через клиентскую JavaScript часть командой перед запуском «убийства» PID:

Socket.close(); socket = null;