1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-24 07:42:22 +01:00
Files
archived-doc-ru/reference/ev/examples.xml
2021-12-23 10:48:40 +03:00

436 lines
14 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 8d666e819852f6b0561b40fcf8689b747568865c Maintainer: rjhdby Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="ev.examples" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
&reftitle.examples;
<example>
<title>Простые таймеры</title>
<programlisting role="php">
<![CDATA[
<?php
// Создаём и запускаем таймер на 2 секунды
$w1 = new EvTimer(2, 0, function () {
echo "2 секунды прошло\n";
});
// Создаём и запускаем таймер, который сработает через 2 секунды, после чего будет срабатывать
// раз в секунду, пока вы его вручную не остановите
$w2 = new EvTimer(2, 1, function ($w) {
echo "вызывается раз в секунду, первое срабатывание через 2 секунды\n";
echo "итерация = ", Ev::iteration(), PHP_EOL;
// Останавливаем наблюдателя через 5 итераций
Ev::iteration() == 5 and $w->stop();
// Остановливаем наблюдателя, если следующий вызов приведёт к десятой (или больше) итерации
Ev::iteration() >= 10 and $w->stop();
});
// Создаём остановленный таймер. Он будет неактивен, пока мы его не запустим
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
echo "Callback-функция таймера, созданного остановленным\n";
// Останавливаем наблюдателя через 2 итерации
Ev::iteration() >= 2 and $w->stop();
});
// Запускаем событийный цикл, пока работает хотя бы один наблюдатель или пока не вызван Ev::stop()
Ev::run();
// Запускаем и смотрим, как он работает
$w_stopped->start();
echo "Запускаем одну итерацию\n";
Ev::run(Ev::RUN_ONCE);
echo "Перезапускаем второго наблюдателя и пытаемся отловить те же события, но не блокируем\n";
$w2->again();
Ev::run(Ev::RUN_NOWAIT);
$w = new EvTimer(10, 0, function() {});
echo "Запускаем блокирующий цикл\n";
Ev::run();
echo "END\n";
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
2 секунды прошло
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 1
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 2
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 3
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 4
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 5
Запускаем одну итерацию
Функция обратного вызова таймера, созданного остановленным
Перезапускаем второго наблюдателя и пытаемся отловить те же события, но не блокируем
Запускаем блокирующий цикл
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 8
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 9
вызывается раз в секунду, первое срабатывание через 2 секунды
итерация = 10
END
]]>
</screen>
</example>
<example>
<title>Периодический таймер. Срабатывает раз в 10.5 секунд</title>
<programlisting role="php">
<![CDATA[
<?php
$w = new EvPeriodic(0., 10.5, NULL, function ($w, $revents) {
echo time(), PHP_EOL;
});
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Периодический таймер. Использование callback-функции для перезадания интервала</title>
<programlisting role="php">
<![CDATA[
<?php
// Срабатывает раз в 10.5 секунд
function reschedule_cb ($watcher, $now) {
return $now + (10.5. - fmod($now, 10.5));
}
$w = new EvPeriodic(0., 0., "reschedule_cb", function ($w, $revents) {
echo time(), PHP_EOL;
});
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Периодический таймер. Срабатывает каждые 10.5 секунд, начиная с текущего момента</title>
<programlisting role="php">
<![CDATA[
<?php
// Срабатывает раз в 10.5 секунд начиная с текущего момента
$w = new EvPeriodic(fmod(Ev::now(), 10.5), 10.5, NULL, function ($w, $revents) {
echo time(), PHP_EOL;
});
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Ждём, пока STDIN не станет читаемым</title>
<programlisting role="php">
<![CDATA[
<?php
// Ждём, пока STDIN не станет читаемым
$w = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) {
echo "STDIN is readable\n";
});
Ev::run(Ev::RUN_ONCE);
?>
]]>
</programlisting>
</example>
<example>
<title>Используем асинхронный ввод/вывод для доступа к сокету</title>
<programlisting role="php">
<![CDATA[
<?php
/* Используем асинхронный ввод/вывод для доступа к сокету */
// Модуль `sockets' продолжит логировать предупреждения
// для EINPROGRESS, EAGAIN/EWOULDBLOCK etc.
error_reporting(E_ERROR);
$e_nonblocking = array (/*EAGAIN или EWOULDBLOCK*/11, /*EINPROGRESS*/115);
// Получаем порт для сервиса WWW
$service_port = getservbyname('www', 'tcp');
// Получаем IP-адрес целевого хоста
$address = gethostbyname('google.co.uk');
// Создаём сокет TCP/IP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === FALSE) {
echo "Ошибка при вызове socket_create(): причина: "
.socket_strerror(socket_last_error()) . "\n";
}
// Устанавливаем флаг O_NONBLOCK
socket_set_nonblock($socket);
// Прерываем по превышению времени ожидания
$timeout_watcher = new EvTimer(10.0, 0., function () use ($socket) {
socket_close($socket);
Ev::stop(Ev::BREAK_ALL);
});
// Посылаем запрос HEAD когда сокет доступен для записи
$write_watcher = new EvIo($socket, Ev::WRITE, function ($w)
use ($socket, $timeout_watcher, $e_nonblocking)
{
// Останавливаем наблюдателя $timeout_watcher
$timeout_watcher->stop();
// Останавливаем наблюдателя $write_watcher
$w->stop();
$in = "HEAD / HTTP/1.1\r\n";
$in .= "Host: google.co.uk\r\n";
$in .= "Connection: Close\r\n\r\n";
if (!socket_write($socket, $in, strlen($in))) {
trigger_error("Ошибка записи $in в сокет", E_USER_ERROR);
}
$read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)
use ($socket, $e_nonblocking)
{
// Сокет доступен для чтения. Читаем 20 байт в неблокирующем режиме
$ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);
if ($ret) {
echo $out;
} elseif ($ret === 0) {
// Все прочтено
$w->stop();
socket_close($socket);
return;
}
// Ловим EINPROGRESS, EAGAIN или EWOULDBLOCK
if (in_array(socket_last_error(), $e_nonblocking)) {
return;
}
$w->stop();
socket_close($socket);
});
Ev::run();
});
$result = socket_connect($socket, $address, $service_port);
Ev::run();
?>
]]>
</programlisting>
&example.outputs.similar;
<screen>
<![CDATA[
HTTP/1.1 301 Moved Permanently
Location: http://www.google.co.uk/
Content-Type: text/html; charset=UTF-8
Date: Sun, 23 Dec 2012 16:08:27 GMT
Expires: Tue, 22 Jan 2013 16:08:27 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Connection: close
]]>
</screen>
</example>
<example>
<title>Встраиваем один цикл в другой</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Пытаемся получить встраиваемый цикл и встроить его в событийный цикл по умолчанию.
* Если это невозможно - используем цикл по умолчанию. Цикл по умолчанию
* хранится в $loop_hi, а встраиваемый в $loop_lo (который будет равен $loop_hi в случае
* если мы не будем использовать встраиваемый цикл).
*
* Пример взят из
* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9
*/
$loop_hi = EvLoop::defaultLoop();
$loop_lo = NULL;
$embed = NULL;
/*
* Смотрим, есть ли возможность получить работающий
* (Значение 0 означает автоопределение)
*/
$loop_lo = Ev::embeddableBackends() & Ev::recommendedBackends()
? new EvLoop(Ev::embeddableBackends() & Ev::recommendedBackends())
: 0;
if ($loop_lo) {
$embed = new EvEmbed($loop_lo, function () {});
} else {
$loop_lo = $loop_hi;
}
?>
]]>
</programlisting>
</example>
<example>
<title>Встраивание цикла, созданного с помощью kqueue в цикл по умолчанию</title>
<programlisting role="php">
<![CDATA[
<?php
/*
* Проверяем, что бэкенд kqueue доступен, но не рекомендован, и создаём его для
* работы с сокетами (которые обычно работают с любой реализацией kqueue).
* Сохраняем событийный цикл kqueue/socket-only в loop_socket. (Можно опционально
* использовать флаг EVFLAG_NOENV)
*
* Пример взят из
* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9
*/
$loop = EvLoop::defaultLoop();
$socket_loop = NULL;
$embed = NULL;
if (Ev::supportedBackends() & ~Ev::recommendedBackends() & Ev::BACKEND_KQUEUE) {
if (($socket_loop = new EvLoop(Ev::BACKEND_KQUEUE))) {
$embed = new EvEmbed($loop);
}
}
if (!$socket_loop) {
$socket_loop = $loop;
}
// теперь используем $socket_loop для всех сокетов, а $loop для всего остального
?>
]]>
</programlisting>
</example>
<example>
<title>Перехватываем сигнал SIGTERM</title>
<programlisting role="php">
<![CDATA[
<?php
$w = new EvSignal(SIGTERM, function ($watcher) {
echo "Получен сигнал SIGTERM\n";
$watcher->stop();
});
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Отслеживаем изменение /var/log/messages</title>
<programlisting role="php">
<![CDATA[
<?php
// Используем интервал опроса в 10 секунд
$w = new EvStat("/var/log/messages", 8, function ($w) {
echo "/var/log/messages изменён\n";
$attr = $w->attr();
if ($attr['nlink']) {
printf("Текущий размер: %ld\n", $attr['size']);
printf("Текущее значение atime: %ld\n", $attr['atime']);
printf("Текущее значение mtime: %ld\n", $attr['mtime']);
} else {
fprintf(STDERR, "файл `messages` отсутствует!");
$w->stop();
}
});
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Отслеживаем изменение /var/log/messages. Избегаем пропуска обновлений с помощью задержки в одну секунду</title>
<programlisting role="php">
<![CDATA[
<?php
$timer = EvTimer::createStopped(0., 1.02, function ($w) {
$w->stop();
$stat = $w->data;
// 1 секунду после последнего изменения файла
printf("Текущий размер: %ld\n", $stat->attr()['size']);
});
$stat = new EvStat("/var/log/messages", 0., function () use ($timer) {
// Сбрасываем наблюдателя $timer
$timer->again();
});
$timer->data = $stat;
Ev::run();
?>
]]>
</programlisting>
</example>
<example>
<title>Отслеживаем изменения статуса процесса</title>
<programlisting role="php">
<![CDATA[
<?php
$pid = pcntl_fork();
if ($pid == -1) {
fprintf(STDERR, "pcntl_fork failed\n");
} elseif ($pid) {
$w = new EvChild($pid, FALSE, function ($w, $revents) {
$w->stop();
printf("Процесс %d вышел с кодом %d\n", $w->rpid, $w->rstatus);
});
Ev::run();
// Защита от зомби процессов
pcntl_wait($status);
} else {
// Порождённый потомок
exit(2);
}
?>
]]>
</programlisting>
</example>
</chapter><!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->