|
例
例1 タイマーのサンプル
<?php // タイマーを作り、2 秒後に起動します $w1 = new EvTimer(2, 0, function () { echo "2 seconds elapsed\n"; });
// タイマーを作って 2 秒後に起動させ、その後は // 手で止めるまで 1 秒おきに繰り返します $w2 = new EvTimer(2, 1, function ($w) { echo "is called every second, is launched after 2 seconds\n"; echo "iteration = ", Ev::iteration(), PHP_EOL;
// 5 回繰り返したあとでウォッチャーを止めます Ev::iteration() == 5 and $w->stop(); // Stop the watcher if further calls cause more than 10 iterations Ev::iteration() >= 10 and $w->stop(); });
// 停止状態のタイマーを作ります。開始させるまでは非アクティブになります。 $w_stopped = EvTimer::createStopped(10, 5, function($w) { echo "Callback of a timer created as stopped\n";
// 2 回繰り返したあとでウォッチャーを止めます Ev::iteration() >= 2 and $w->stop(); });
// Ev::stop() が呼ばれるか、すべてのウォッチャーが止まるまでループします Ev::run();
// 開始させ、うまく動いているかどうかを確認します $w_stopped->start(); echo "Run single iteration\n"; Ev::run(Ev::RUN_ONCE);
echo "Restart the second watcher and try to handle the same events, but don't block\n"; $w2->again(); Ev::run(Ev::RUN_NOWAIT);
$w = new EvTimer(10, 0, function() {}); echo "Running a blocking loop\n"; Ev::run(); echo "END\n"; ?>
2 seconds elapsed
is called every second, is launched after 2 seconds
iteration = 1
is called every second, is launched after 2 seconds
iteration = 2
is called every second, is launched after 2 seconds
iteration = 3
is called every second, is launched after 2 seconds
iteration = 4
is called every second, is launched after 2 seconds
iteration = 5
Run single iteration
Callback of a timer created as stopped
Restart the second watcher and try to handle the same events, but don't block
Running a blocking loop
is called every second, is launched after 2 seconds
iteration = 8
is called every second, is launched after 2 seconds
iteration = 9
is called every second, is launched after 2 seconds
iteration = 10
END
例2 10.5 秒おきに繰り返すタイマー
<?php $w = new EvPeriodic(0., 10.5, NULL, function ($w, $revents) { echo time(), PHP_EOL; });
Ev::run(); ?>
例3 再スケジュールコールバックを使う定期タイマー
<?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(); ?>
例4 すぐに開始し、10.5 秒おきに繰り返すタイマー
<?php // すぐに開始し、10.5 秒おきに繰り返します $w = new EvPeriodic(fmod(Ev::now(), 10.5), 10.5, NULL, function ($w, $revents) { echo time(), PHP_EOL; });
Ev::run(); ?>
例5 STDIN が読み込み可能になるまで待つ例
<?php // STDIN が読み込み可能になるまで待ちます $w = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) { echo "STDIN is readable\n"; });
Ev::run(Ev::RUN_ONCE); ?>
例6 非同期 I/O を使ったソケットへのアクセス
<?php /* 非同期 I/O を使ってソケットにアクセスします */
// `sockets' 拡張モジュールは、 // EINPROGRESS や EAGAIN/EWOULDBLOCK などに対して warning を発光します error_reporting(E_ERROR);
$e_nonblocking = array (/*EAGAIN or 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() failed: reason: " .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->stop(); // 書き込みのウォッチャーを止めます $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("Failed writing $in to socket", E_USER_ERROR); }
$read_watcher = new EvIo($socket, Ev::READ, function ($w, $re) use ($socket, $e_nonblocking) { // ソケットが読み込み可能になりました。非ブロックモードで 20 バイト recv() します $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(); ?>
HTTP/1.1 301 Moved Permanently
Location: //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
例7 ループの中に別のループを埋め込む例
<?php /* * 埋め込み可能なイベントループをデフォルトのイベントループに組み込みます。 * できなかった場合はデフォルトのループを使います。 * デフォルトのループは $loop_hi に、そして埋め込み可能なループは $loop_lo * に格納されます (埋め込み可能なループが使えなかった場合は $loop_hi * を使います)。 * * このサンプルを PHP に移植したものです。 * 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; } ?>
例8 kqueue バックエンドで作ったループをデフォルトのループに埋め込む例
<?php /* * kqueue が使えるかどうかを調べ、ソケットで使う 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 を使うようになりました ?>
例9 SIGTERM の処理
<?php $w = new EvSignal(SIGTERM, function ($watcher) { echo "SIGTERM received\n"; $watcher->stop(); });
Ev::run(); ?>
例10 /var/log/messages の変更の監視
<?php // 更新間隔を 10 秒にします $w = new EvStat("/var/log/messages", 8, function ($w) { echo "/var/log/messages changed\n";
$attr = $w->attr();
if ($attr['nlink']) { printf("Current size: %ld\n", $attr['size']); printf("Current atime: %ld\n", $attr['atime']); printf("Current mtime: %ld\n", $attr['mtime']); } else { fprintf(STDERR, "`messages` file is not there!"); $w->stop(); } });
Ev::run(); ?>
例11 /var/log/messages の変更の監視 (1 秒の遅延を使って、更新を見落とさないようにする)
<?php $timer = EvTimer::createStopped(0., 1.02, function ($w) { $w->stop();
$stat = $w->data;
// ファイルへの直近の変更から 1 秒後 printf("Current size: %ld\n", $stat->attr()['size']); });
$stat = new EvStat("/var/log/messages", 0., function () use ($timer) { // タイマーウォッチャーをリセットします $timer->again(); });
$timer->data = $stat;
Ev::run(); ?>
例12 ステータスの変更の処理
<?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("Process %d exited with status %d\n", $w->rpid, $w->rstatus); });
Ev::run();
// ゾンビ対策 pcntl_wait($status); } else { // フォークした子プロセス exit(2); } ?>
|
|
|