Что такое сокет в PHP
Не так давно меня попросили рассказать про сокеты на PHP. Вообще я планирую написать ещё несколько статей в ближайшее время по этой теме, а в этой статье я расскажу о том, что такое сокеты в PHP. Чтобы Вы уже могли понять, нужны они Вам или нет.
Сокет — это интерфейс взаимодействия клиента и сервера. Интерфейс — это, в свою очередь, правило, по которым происходит общение между клиентом и сервером. Чтобы стало понятнее, приведу пример из обычной жизни. Например, люди общаются с помощью слов на конкретном языке. Это наш с Вами интерфейс. В зависимости от входящих слов мы формируем образ у себя в голове, и отдаём ответ, в виде опять же слов. Другой пример, дельфины общаются в ультразвуком спектре, и это их интерфейс.
Надеюсь, про интерфейс теперь понятно, это правило взаимодействия. Теперь про клиента. Клиентом может выступать как человек, формирующий определённые запросы к серверу, так и программа, написанная на любом языке программирования, способном обмениваться данными с удалённым сервером. Сервер — это машина, ждущая подключения клиентов, принимающая от них запросы, и в зависимости от запросов, возвращающая ответ.
Кратко резюмирую, что же такое сокет: есть клиент, есть сервер, есть правила взаимодействия (интерфейс), клиент, согласно этим правилам, посылает запрос, а сервер данный запрос принимает и, согласно тем же правилам, даёт ответ.
Как видите, всё совсем не сложно. Очень здорово то, что клиент и сервер могут быть написаны на совсем разных языках программирования и могут находиться друг от друга за тысячи километров. Мы же с Вами будет писать и клиент, и сервер в будущих статьях на языке PHP.
Создано 13.01.2012 14:01:12
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
- Кнопка:
Она выглядит вот так: - Текстовая ссылка:
Она выглядит вот так: Как создать свой сайт - BB-код ссылки для форумов (например, можете поставить её в подписи):
Комментарии ( 2 ):
ankalitkin 14.01.2012 09:57:37
А способ взаимодействия клиента и сервера может называться протоколом? Например ftp.
Программирование сокетов на PHP
Работа посвещена программированию сокетов на PHP. Для сетевого взаимодействия в PHP существует две категории функций:
- Функция fsockopen(string hostname, integer port, integer error_number, string error_description, double timeout) — она открывает сетевое соединение как файловый поток и возвращает дискриптор файла с которым работают функции fputs, fgets и т.д.
- Функции которые передают информацию непосредственно на уровне IP-протокола. И это гораздо более низкий уровень по сравнению с уровнем на котором работает функция fsockopen.
Рассматриваться будут только функции под номером 2, т.к. они более интересны.
Для начала проверим, подключена ли у Вас библиотека работы с сокетами.
Проверить это можно следующим скриптом:
if(extension_loaded('sockets')) echo "WebSockets OK"; else echo "WebSockets UNAVAILABLE";
Если расширение не подключено, то Вам следует его подключить.
Итак. Наиболее простой в рамках статьи пример — echo-сервер. Эхо-сервер — это означает, что строка отправленная клиентом серверу, возвращается обратно. То есть сервер получает какое-то сообщение от клиента, что-то с ним делает и отправляет ему обратно.
У нас будет 2 скрипта:
- Сервер или демон (daemon).
- Клиент.
Скрипт «Клиент».
Для реализации клиента нам понадобятся следующие функции работающие с сокетами:
- 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 в зависимости от типа.
- socket_connect(resource socket, string address, integer port); — после создания сокета необходимо к нему подключится. Первым аргументом является ресурс созданного сокета, вторым IP адрес сокета если семейство протокола AF_INET, или pathname сокета Unix-домена если сокет из семейства AF_UNIX. Третьем агрументом является номер порта с которым должно быть установлено соединение.
- socket_read(resource socket, integer length, integer type); — функция считывает заданное в аргументе lenght количество байт из указанного сокета. По умолчанию чтение производится без учета управляющих символов, или можно задать в аргументе type — PHP_BINARY_READ, для учета управляющих символов необходимо задать значение PHP_NORMAL_READ.
- socket_write(resource socket, string buffer, integer length); — функция записывает данные в сокет.
- socket_close(resource socket); — закрывает сокет и освобождает память.
Листинг 1.0 — Клиент
<?php header('Content-Type: text/html; charset=utf-8'); $address = '127.0.0.1'; // адрес localhost. $port = 5555; // порт с которым будет установлено соединение. echo "Создание сокета. "; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket < 0) < echo "Ошибка: ".socket_strerror(socket_last_error()).""; >else < echo "OK"; >echo "Подключение к сокету. "; $connect = socket_connect($socket, $address, $port); if($connect === false) < echo "Ошибка : ".socket_strerror(socket_last_error()).""; >else < echo "OK"; echo 'Сервер сказал: '; $awr = socket_read($socket, 1024); echo $awr.""; $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)) ?>
Скрипт «Сервер».
Для реализации сервера нам понадобятся следующие функции работающие с сокетами:
- Все те функции которые были описаны выше.
- socket_bind(resource socket, string address, integer port); — функция привязывает адрес к сокету. Аргумент addres — IP адрес сокета если семейство протокола AF_INET, или pathname сокета Unix-домена если сокет из семейства AF_UNIX.
- socket_listen(resource socket, integer backlog) — функция прослушивает входящие соединения в сокет. Необязательный второй аргумент устанавливает максимальный размер очереди запросов, ожидающих соединения.
- socket_accept(resource socket); — После того как сокет создан, привязан, и начал прослушивание, именно эта функция делает сервер сервером. Функция принимает входящие соединения.
Листинг 1.1 — Сервер
<?php header('Content-Type: text/html; charset=utf-8'); $address = '127.0.0.1'; $port = 5555; echo "Создание сокета . "; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if($socket < 0) else echo "Привязывание сокета. "; $bind = socket_bind($socket, $address, $port); if($bind < 0) else echo "Прослушивание сокета. "; $listen = socket_listen($socket, 5); if($listen < 0) else while(true) else $msg = "Hello, Клиент!"; echo "Отправить клиенту \"".$msg."\". "; socket_write($accept, $msg, strlen($msg)); echo "OK"; while(true) else if ($awr == 'exit') echo "Сказать клиенту \"".$msg."\". "; socket_write($accept, $awr, strlen($awr)); echo "OK";> > if (isset($socket)) ?>
Вначале запустите скрипт сервер, он создаст, привяжет, начнёт прослушивание сокета и установится в режим ожидания клиента. Далее запустите клиента.
Введение
Модуль socket реализует низкоуровневый интерфейс для функций связи сокетов, основанными на популярных сокетах BSD, обеспечивая возможность действовать как сервер сокетов, так и клиент.
При использовании этих функций, важно помнить, что хотя многие из них имеют имена, похожие на их аналоги в C, они часто имеют другой интерфейс использования. Пожалуйста, прочитайте их описания для того, чтобы избежать путаницы.
Незнакомые с программированием сокетов могут найти много полезной информации в соответствующих man-страницах Unix, также в Интернете есть много обучающей информации по программированию сокетов на C, большая часть из которой может быть применена с небольшими изменениями к программированию сокетов на PHP. Хорошим началом может быть » FAQ по Unix-сокетам.
User Contributed Notes
There are no user contributed notes for this page.
- Copyright © 2001-2023 The PHP Group
- My PHP.net
- Contact
- Other PHP.net sites
- Privacy policy
Работа с Веб-сокетами на PHP
PHP — едва ли первое, что придет в голову, когда стоит задача поднять сервер веб-сокетов. Практически каждая статья в интернете будет пестрить предложениями использовать для этого NodeJS, Python или Go. Но поскольку PHP — это однозначно первое, что приходит в голову, когда речь идет о веб-приложениях, почему бы не попробовать?
На самом деле, запуск сервера веб-сокетов на PHP довольно прост. Существует превосходная библиотека Ratchet, позволяющая работать на любом фреймворке (или вовсе без него) полноценно и легко.
Казалось бы, на этом разговор можно заканчивать, но мы неизбежно столкнемся с некоторыми ограничениями и проблемами, связанными с архитектурой конечного приложения и природой самого протокола веб-сокетов.
Авторизация
По умолчанию, сервер веб-сокетов открыт для любого подключения. Конечно, можно поставить сетевые ограничения по доменам или IP адресам, но для веб-приложения — это, мягко говоря, не эффективный подход. В обычной ситуации мы используем для таких ограничений тот или иной вариант сервиса авторизации — токены, сессии и т.д. Здесь же проблема в том, что мы не сможем отправить через протокол ws:// ни HTTP заголовок, ни cookies. Значительная часть привычных методов, таким образом, не сработает.
Архитектура
Основное приложение != сервер веб-сокетов. Для работы с ними всегда необходимо держать в голове, что мы имеем дело с двумя отдельными приложениями, вне зависимости от того, насколько тесно они взаимодействуют между собой. На первый взгляд это может показаться незначительным нюансом, однако такое положение вещей требует особого внимания к подготовке интерфейсов для интеграции основного приложения и сервера веб-сокетов. Ко всему прочему, это порождает еще одну проблему.
База данных
Поскольку сервер веб-сокетов — это отдельное от основного бэкенда приложение, он ничего не знает о существующей базе данных. Сложно представить себе современное приложение на PHP, написанное без использование какого-либо фреймворка и ORM, так что перед разработчиком встанет дополнительная задача интегрировать службы, сервисы и библиотеки для работы с БД в сторонний скрипт.
Решения
Для каждой из названных проблем вполне возможно отыскать соответствующее решение. Некоторые из потенциальных решений могут показаться шероховатыми, но главное, что они рабочие.
Авторизуем пользователей
В процессе подключения к серверу веб-сокетов существует этап, на котором исходный HTTP запрос преобразуется в WS запрос. Используемая нами библиотека Ratchet сохраняет этот начальный запрос в объекте Connection. Хотя возможности подцепить Bearer заголовок к запросу нет (для клиентского приложения запрос строится сразу как ws://websocket-server), мы можем передать токен (например, JWT) в параметрах запроса. При использовании HTTPS — это вполне безопасный способ передачи.
В итоге, запрос на подключение может выглядеть примерно так:
Строку параметров затем можно извлечь из упомянутого ранее объекта Connection.
После извлечения токен может использоваться в любом уже применяющемся механизме авторизации, реализованном в основном приложении.
Интегрируем базу данных
В 9 из 10 случаев основное приложение будет написано на одном из популярных фреймворков вроде Laravel или Symfony. Все, что нам необходимо реализовать в такой ситуации — внедрение службы, отвечающей за ORM, в конструктор сервера веб-сокетов. При условии, что для запуска сервера используется консольная команда, использующая компонент Symfony Console, мы можем сделать это в два этапа: первоначальной инъекцией в конструктор консольной команды, а оттуда передачей в конструктор основного класса веб-сокетов.
Разделяем приложения
Раз уж мы вынуждены расценивать основное приложение и сервер веб-сокетов как два отдельных компонента, ничто не мешает нам использовать API основного приложения внутри сервера веб-сокетов. Пожалуй, самый распространенный сценарий — сохранение сообщений в БД и последующая отдача их фронтенд-приложению.
В целом, после внедрения ORM в обработчик веб-сокетов, мы могли бы выполнять все это с помощью обычных CRUD-операций. Но гораздо более эффективным решением было бы использовать уже готовый API. Почему? Во-первых, это позволит избежать дублирования кода (ровно такие же CRUDы используются в контроллерах, отвечающих за API). Во-вторых, таким способом мы укладываемся в общую архитектуру разделенных компонентов, даже внутри монолитного решения. Более того, имея одновременно токен из исходного запроса и внедренный ORM, мы получаем возможность авторизовывать действия и валидировать данные при абсолютно каждом событии веб-сокетов, а это уже полноценная имперсонификация пользователя.
Выводы
PHP все еще может быть не первым вариантом для работы с веб-сокетами, но на нем все еще вполне возможен запуск и эксплуатация полноценного сервера веб-сокетов со всеми необходимыми соображениями безопасностями и прозрачной архитектуры.