- Что такое сокет в PHP
- Комментарии ( 2 ):
- Функции сокета
- Содержание
- User Contributed Notes 19 notes
- Вебсокеты на php. Выбираем вебсокет-сервер
- phpdaemon
- Ratchet
- Workerman
- Делаем вебсокеты на PHP с нуля
- Поставленные цели:
- 1) Серверные сокеты в php
- 2) Протокол вебсокетов
- Простой сервер вебсокетов
- PHP: Программирование сокетов
- Основы сокетов
- Создание нового сокета
- Константы доменов для сокеткых соединений
- Константы типов сокетов
- Ошибки сокетов
- Создание клиентских сокетов.
- Константы типа для socket_read()
- Создание серверных сокетов
- Создание простого сервера на основе сокета
- Одновременная работа с несколькими сокетами
- Создание многосортного сервера на РНР
Что такое сокет в PHP
Не так давно меня попросили рассказать про сокеты на PHP. Вообще я планирую написать ещё несколько статей в ближайшее время по этой теме, а в этой статье я расскажу о том, что такое сокеты в PHP. Чтобы Вы уже могли понять, нужны они Вам или нет.
Кратко резюмирую, что же такое сокет: есть клиент, есть сервер, есть правила взаимодействия (интерфейс), клиент, согласно этим правилам, посылает запрос, а сервер данный запрос принимает и, согласно тем же правилам, даёт ответ.
Как видите, всё совсем не сложно. Очень здорово то, что клиент и сервер могут быть написаны на совсем разных языках программирования и могут находиться друг от друга за тысячи километров. Мы же с Вами будет писать и клиент, и сервер в будущих статьях на языке PHP.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 2 ):
А способ взаимодействия клиента и сервера может называться протоколом? Например ftp.
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
Функции сокета
Содержание
User Contributed Notes 19 notes
After many non-sleep nights I got the most simple multi-client server written in PHP that really works. Ctrl+C and Ctrl+V. use as command line to test it. Enjoy it.
// Set time limit to indefinite execution
set_time_limit ( 0 );
// Set the ip and port we will listen on
$address = ‘10.203.9.67’ ;
$port = 6901 ;
Planning on sending integer values through as socket, I was surprised to find PHP only supports sending strings.
I came to the conclusion the only way to do it would be to create a string that would evaluate to the same byte values as the integer I wanted to send. So (after much messing about) I created a couple of functions: one to create this ‘string’ and one to convert a received value back to an integer.
A multicast server can be written badly as follows:
Checking the return types is needed, but this does allow for you to multicast from php code.
I have searched long and hard for a ping script that does NOT use EXEC() or SYSTEM(). So far, I have found nothing, so I decided to write my own, which was a task to say the least.
First off, I would like to thank Khaless for their checksum function, converting it from C looked like a task in itself.
function Build_Packet ()
<
$data = «abcdefghijklmnopqrstuvwabcdefghi» ; // the actual test data
$type = «\x08» ; // 8 echo message; 0 echo reply message
$code = «\x00» ; // always 0 for this program
$chksm = «\x00\x00» ; // generate checksum for icmp request
$id = «\x00\x00» ; // we will have to work with this later
$sqn = «\x00\x00» ; // we will have to work with this later
?>
Hope this saves some troubles.
Вебсокеты на php. Выбираем вебсокет-сервер
Давным-давно я публиковал статью на хабре, как написать свой вебсокет-сервер с нуля. Статья переросла в библиотеку. Несколько месяцев я занимался её развитием, ещё несколько лет — поддержкой и багфиксом. Написал модуль интеграции с yii2. Какой-то энтузиаст написал интеграцию с laravel. Моя библиотека совместима с php7. Недавно я решил отказаться от её дальнейшей поддержки (причины ниже), поэтому хочу помочь её пользователям перейти на другую библиотеку.
Прежде чем начать писать свой вебсокет-сервер, я выбирал из готовых продуктов, и на тот момент их было всего два: phpdaemon и ratchet.
phpdaemon
Ratchet
В итоге я написал библиотеку для себя и поделился ею с сообществом на гитхабе. Сделал несколько демок (в том числе игру «танчики»). Переписал стороннюю игру (с разрешения авторов) с node.js на свою библиотеку. Делал нагрузочное тестирование. Демки работали годами без перезагрузки. Старался отвечать на тикеты в течения дня. Всё это показывало, что моя библиотека может быть использована на продакшене и многие её использовали.
Была единственная проблема. Мне хватало моей библиотеки для использования в своих проектах, а вот другим нет. Они хотели, чтобы я её развивал, а мне это было не нужно. Кому-то требовалась поддержка windows, а кому-то ssl, pg_notify, safari, pthreads и многое другое. Открытые тикеты с запросами на реализацию различного функционала висят годами.
Не так давно, я решил пересмотреть ещё раз, какие продукты могут быть полезны для пользователей моей библиотеки и был приятно удивлён, что кроме двух проектов, описанных выше появился ещё третий. Он полностью удовлетворял моим запросам и даже больше.
Workerman
Если загуглить «php websocket», то первая страница — это моя статья на Хабре, а вторая — «Ratchet», который кому-то может показаться сложным и он выберет из-за этого мою библиотеку или вообще откажется от идеи делать вебсокеты.
Что ж, пришло время исправить эту досадную ошибку и донести до как можно большего количества людей о существовании такой библиотеки как Workerman и привести несколько примеров по её использованию.
На главной странице проекта в гитхабе уже есть несколько примеров. Рассмотрим один из них:
В принципе, используя первый пример можно сделать чат на вебсокетах и других примеров не нужно. Но за несколько лет я понял, что в основном пользователям моей библиотеки был нужен пример того как можно отправить из своего кода на php уведомление выбранному пользователю, а не всем одновременно, как часто бывает в примерах.
код сервера server.php:
код клиента client.html:
код отправки сообщений с нашего сайта send.php:
Справедливости ради я решил написать такой же пример для ratchet, но документация мне не помогла, как 3 года назад. Зато на stackoverflow предложили немного костыльный, но рабочий вариант: соединяться из своего php-скрипта по ws-соединению. Конечно это не так же просто как соединиться с tcp-сокетом с помощью stream_socket_client и отправить сообщение с помощью fwrite. Но уже что-то.
Плюс ещё остался для меня незакрытый вопрос: поддерживает ли ratchet возможность запуска нескольких воркеров и если да, то как в таком случае отправлять сообщение одному пользователю, ведь не понятно на каком он воркере. На workerman это можно сделать так.
В общем, я выбрал для себя библиотеку Workerman и рекомендую переходить на неё пользователям моей библиотеки. Все примеры лежат на гитхабе.
Update: в комментариях рекомендуют swoole. Я натыкался на эту библиотеку ранее, но у меня сложилось ложное впечатление, что что она не поддерживает php7 и после этого она выпала из моего круга зрения. А зря. Интересная библиотека.
Делаем вебсокеты на PHP с нуля
Некоторое время назад я выбирал библиотеку для работы с вебсокетами. На просторах интернета я натыкался на статьи по интеграции node.js с yii, а почти все статьи о вебсокетах на хабре ограничивались инструкциями к тому, как использовать phpdaemon.
Я изучал библиотеки phpdaemon и ratchet, они достаточно монструозны (причём используя ratchet для отправки сообщения конкретному пользователю рекомендовано дополнительно использовать wamp). Мне не совсем было понятно для чего использовать таких монстров, которые требуют установку других монстров. Почитав исходники этих, а также других библиотек, я разобрался как всё устроено и мне захотелось написать простой вебсокет-сервер на php самостоятельно. Это помогло мне закрепить изученный материал и наткнуться на некоторые подводные камни, о которых я не имел представления.
Так я решил написать необходимый для меня функционал с нуля.
Получившийся код и ссылка на демонстрационный чат в конце статьи.
Поставленные цели:
1) разобраться с серверными сокетами в php
2) разобраться с протоколом вебсокетов
3) написать с нуля простой сервер вебсокетов
1) Серверные сокеты в php
До этого момента я имел смутные представления о серверных сокетах. Почитав исходники нескольких библиотек для работы с вебсокетами я столкнулся с двумя схемами их реализаций:
используя расширение php «socket»:
или используя расширение php «stream»:
Я предпочёл второй вариант ввиду его краткости.
Итак, мы создали серверный сокет и теперь хотим обрабатывать новые соединения к нему, для этого опять же есть два варианта
или с использованием stream_select
Т.к. нам в дальнейшем нужно будет одновременно обрабатывать и серверный сокет на предмет новых соединений, и уже существующие подключения, на предмет новых сообщений, то остановимся на втором варианте.
2) Протокол вебсокетов
«Рукопожатие» или handshake:
Считываем значение Sec-WebSocket-Key из пришедшего заголовка от клиента, рассчитываем на его основе Sec-WebSocket-Accept и отправляем итоговый ответ:
обмен сообщениями
Простой сервер вебсокетов
Итак, у нас есть вся необходимая информация.
Используя код простого http сервера из первой части, а также функции handshake, decode и encode из второй мы можем собрать простой сервер вебсокетов.
В приведённом примере можно менять пользовательские сценарии onOpen, onClose и onMessage для реализации необходимого функционала.
Поставленные цели достигнуты.
Если этот материал вам покажется интересным, то в следующей статье я опишу как можно запускать несколько процессов для обработки соединений (один мастер и несколько воркеров), межпроцессное взаимодействие, интеграцию с вашим фреймворком на примере компонента yii.
PHP: Программирование сокетов
Сокеты представляют собой чрезвычайно удобную, но в то же время плохо понятую технологию взаимодействия между двумя процессами в сети. Эти процессы могут существовать на одной и той же машине, общаясь друг с другом через локальный сокет, предназначенный для взаимодействия между процессами, либо на разных машинах через Internet. Хотя тема сокетов очень обширна, в данной статье представлены основы, которые необходимы для использования расширений РНР, предназначенных для написания собственных серверов и клиентов сокетов.
�?мейте в виду, что примеры, приведённые далее в этой статье, разработаны для запуска непосредственно из окружения оболочки с использованием версии РНР командной строки. Хотя их можно запустить в Web-браузере, делать это не рекомендуется. В случае сценариев, которые создают серверы сокетов, их применение можно продемонстрировать с помощью любых программ, способных устанавливать сетевое соединение через сокеты, например, telnet (что, собственно, и рекомендуется).
Основы сокетов
Сокеты могут быть надежными, выполняющими все необходимое для обеспечения передачи данных из точки А в точку В (TCP), либо ненадежными, когда данные передаются без гарантии доставки (UDP).
Сокеты также бывают «блокирующими» и «неблокирующими». Блокирующие сокеты заставляют ваше приложение ожидать до тех пор, пока данные станут доступны, в то время как неблокирующие сокеты этого не делают. Хотя, как будет показано далее, все сокеты двунаправлены, все же существует разница между сокетами клиента и сервера.
Мы с вами рассмотрим ТСР-сокеты Internet, поскольку они наиболее широко используются на сегодняшний день. Тем не менее, концепции и примеры кода, приведенные здесь, применимы к большинству операций с сокетами.
Создание нового сокета
Независимо от типа создаваемого сокета (клиентский или серверный), все они инициализируются одинаковым способом — с помощью функции socket_create(). Синтаксис этой функции выглядит следующим образом:
В результате выполнения эта функция либо возвращает ресурс, представляющий созданный сокет, либо булевское значение false в случае ошибки.
Константы доменов для сокеткых соединений
Константа | Описание |
---|---|
AF_INET | Протокол Internet IPv4 |
AF_INET6 | Протокол Internet IPv6 |
AF_UNIX | Локальное межпроцессное взаимодействие |
После того, как домен установлен, нужно определить Т�?П подключения для создаваемого сокета. Эти типы перечислены в следующей таблице:
Константы типов сокетов
Константа | Описание |
---|---|
SOCK_STREAM | Последовательный надежный двунаправленный поток, основанный на подключении. �?спользуется наиболее часто. |
SOCK_DGRAM | Ненадежный сокет, без подключения, передающий данные фиксиро ванной длины. Очень хорош для потоков данных, в которых надеж ность не критична. |
SOCK_SEQPACKET | Подобен потоковым сокетам за исключением того, что данные пере даются н принимаются в виде пакетов фиксированной длины. |
SOCK_RAW | Неформатированное сокетное подключение, удобное для выполне ния операций ICMP (Internet Control Message Protocol — протокол управляющих сообщений Internet), таких как trace, ping и так далее. |
SOCK_RDM | Надежный, по непоследовательный сокет, подобный SOCK DGRAM. |
Как видите, существует множество опций при выборе типа создаваемых сокетов. Вообще большинство сокетных соединений устанавливается с помощью сокетов SОСК_STREAM или SOCK_DGRAM. Учитывая очевидную полноту SOCK_STREAM (большая часть Internet работает по этому типу сокетов через TCP), может быть не совсем понятно, зачем нужны сокеты типа SOCK_DGRAM (используемые с протоколом UDP).
В конце концов, почему вообще вам может понадобиться «ненадежный» способ передачи данных? Ответ становится очевидным, когда возникает необходимость в получении постоянного потока данных, который обрабатывается в реальном времени, от сервера к клиенту. Поскольку для приложений подобного типа потерянные пакеты несущественны (поскольку такие приложения имеют дело с данными, привязанными ко времени, которые быстро устаревают), нет необходимости в повторной отправке пакетов.
Мы будем испольэовать сокеты Internet IPv4 типа SOCK_STREAM, работающие через соединения SOL_TCP (TCP), После того, как ресурс сокета создан, он может быть уничтожен с помощью функции socket_close(), имеющей следующий синтаксис:
socket_close($socket);
Ошибки сокетов
socket_last_error($socket);
socket_strerror($error_code);
Создание клиентских сокетов.
Создание сокета, готового для подключения к другому сокету в Internet, выполняется с помощью функции socket_connect ():
$socket — это сокет для записи данных;
Когда эта функция выполняется, она отправляет содержимое буфера через подключенный сокет и возвращает количество записанных байт, либо булевское значение false в случае возникновения ошибки.
Для чтения данных из сокета применяется функция socket_read<) со следующим синтаксисом:
Константы типа для socket_read()
Константа | Описание |
---|---|
PHP_BINARY_READ | �?нтерпретировать данные как бинарные (поумолчанию). |
PHP_NORMAL_READ | Читать данные заданной длины, либо пока не встретится символ новой строки (\r или \n). |
В листинге ниже представлен пример использования сокетов для извлечения индексной страницы Web-сайта, в него включено все, что рассматривалось выше. �?звлечение индексной страницы осуществляется отправкой простого GET-запроса HTTP 1.0 с последующим чтением результата в переменную.
Создание серверных сокетов
Когда осуществляется привязка к адресу, убедитесь, что ваш сокет не допустит подключений к чему-либо другому, кроме указанного адреса и порта! Это означает, что привязка сокета к локальному хосту (127.0.0.1) позволит вашему сокету принимать топько покальные подключения.
Второй шаг: настроить сокет на прослушивание трафика на предмет попыток подключения к нему. Это делается с помощью функции socket_listen():
Третий и последний шаг в создании серверного сокета — дать команду на прием входящих подключений. Это делается функцией socket_accept ():
socket_accept($socket);
В листинге ниже создается простой сокетный сервер, принимающий единственное подключение, максимум 1024 байта входного потока и отображающий этот поток пользователю.
Создание простого сервера на основе сокета
У меня на компе этот скрипт лежит в папке денвера по пути: C:\WebServers\home\app.loc\www\sockets\test.php
Теперь, если запустить наш скрипт из командной строки таким макаром: C:\WebServers\home\app.loc\www\sockets>php test.php В командной строке мы увидим следующее:
Сервер в ответ пришлёт нам наш же запрос + заголовки:
В командной строке мы увидим новые данные
Чтобы создать сервер, сокеты которого ведут прослушивание на портах с номерами ниже 1000, данный пользователь должен иметь в системе административные права. Также следует отметить, что приведенный выше сценарий не завершит работу до тех пор, пока не будет установлено соединение, что может создать впечатление «зависания».
Одновременная работа с несколькими сокетами
В листинге, на предыдущей странице был представлен сервер на базе сокетов. Однако он не слишком удобен для реальных, целей, поскольку к нему может выполняться только одно подключение одновременно. Чтобы создать более удобный сервер сокетов, необходимо научиться работать одновременно с множеством сокетов. Чтобы сделать это, понадобится функция socket_select (), синтаксис которой выглядит следующим образом:
В случае ошибочного завершения socket_select() возвращает булевское значение false.
Для использования этой функции в реальном приложении первым делом должен быть создан сокет, представляющий сервер в целом. Этот главный сокет будет привязан к определенному адресу и порту и начнет прослушивание подключений.
Этот новый подключенный сокет затем подвергается мониторингу через тот же вызов socket_select() (за счет добавления его к тому же массиву, куда уже добавлен наш главный сокет) и реализуется логика приложения, обеспечивающая функциональность нашего сервера. В листинге ниже представлен работающий пример простого сервера, принимающего настраиваемое число подключений.
Создание многосортного сервера на РНР
В листинге выше вскрыты некоторые ограничения сценарного механизма РНР, которые требуют несколько более сложного обходного пути в форме вызова socket_select():
$NULL = NULL;
�? последующей ее передачи функции socket_select().