@corecode
php backend development

Могут ли в PHP сокеты работать асинхронно?

Здравствуйте, друзья! Кто работал с сокетами на пыхе, подскажите, плз!

Есть родительский процес, который форкается. В дочернем должен выполнятся некий условно-бесконечный цикл, выполняющий определенную работу и который надо контролировать с помощью tcp-сокетов. Контроль заключается в том, что через сокет должны отдаваться данные об актуальном состоянии цикла и приниматься команды, например на его прерывание. Но вот проблема: при чтении данных из сокета выполнение скрипта останавливается в ожидании ввода на функции socket_read(), и, соответственно не может выполнять полезную работу до того, как получит что то на входе.

По идее для этого есть возможность для сокета задавать флаг O_NONBLOCK с помощью функции socket_set_nonblock(), но не понятно как дальше с этим работать. Примеров использования неблокирующих сокетов практически нигде нет. При неблокирующем сокете socket_accept() возвращает false.

Ниже могу привести лишь пример блокирующего сокета:
<?php

header('Content-Type: text/html;');

set_time_limit(40);

ob_implicit_flush();

echo "Start<br>\n";

function someUsefullWork() {
    static $var = 0;
    $var++;
    return $var;
}

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '127.0.0.1', 7890);
socket_listen($socket, 5); // max 5 connections
$timeout = 15; // timeout in seconds
$tStart = microtime(true);
$tSpent = 0;
do {
    $connect = socket_accept($socket);
    $buffer = "Hello client!\n";
    socket_write($connect, $buffer, strlen($buffer));
    $buffer = trim(socket_read($connect, 4096));
    echo "Command: {$buffer}\n<br>";
    socket_close($connect);
    if ($buffer === 'exit') {
        break;
    }
    someUsefullWork();
} while ((microtime(true) - $tStart) < $timeout);
if (isset($socket)) {
    socket_close($socket);
}
echo someUsefullWork();

?>


В результате работы скрипта рабочая функция вернёт кол-во попыток писать в сокет из клиента. Конечной же целью задачи является получение большого количества вызовов из цикла, ограниченного в данном примере таймаутом.
В качетсве клиента использую телнет:
$ telnet 127.0.0.1 7890
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Hello client!
exit
Connection closed by foreign host.


Вывод в браузере:
Start
Client says: exit 
1


Буду благодарен за любую помощь!
  • Вопрос задан
  • 1034 просмотра
Пригласить эксперта
Ответы на вопрос 2
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
Могут ли в PHP сокеты работать асинхронно?


Да. Это называется non blocking sockets а не "асинхронно".

но не понятно как дальше с этим работать.


socket_select.
Ответ написан
Согласен с Сергей Протько
От себя добавлю: вместо расширения socket используй лучше расширение stream: функции stream_socket_* и stream_select

Так же можно использовать неблокирующие библиотеки для "асинхронной" работы с сокетами: ReactPHP/Socket (сервер), ReactPHP/Socket (клиент) или IcicleIO/Socket (и клиент, и сервер)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы