Webソケットサーバーの作成を開始する前に、既製の製品から選択しましたが、当時はphpdaemonとratchetの2つしかありませんでした。
phpdaemon
GitHubで1,400つ星
- libeventライブラリのインストールに依存
- プロトコル:HTTP、FastCGI、FlashPolicy、Ident、Socks4 / 5。
ラチェット
GitHubで3,600つ星
- 十数個の依存関係を引き出します
- プロトコル:websocket、http、wamp
- Windowsサポート
- SSLなし
これらのライブラリは非常に巨大であり、同時に私の内部要件を満たしていませんでした。
- 依存関係の欠如
- タイマーの存在
すべてのユーザー間のインタラクションを0.05秒ごとに計算するために、Webソケットでゲームを作成するタイマーが必要でした。
最後に、私は自分でライブラリを作成し、 githubでコミュニティと共有しました。 彼はいくつかのデモを作成しました(ゲームの「タンク」を含む)。 node.jsからライブラリにサードパーティのゲームを(作成者の許可を得て)書き直しました。 負荷テストを行いました。 デモは再起動なしで何年も機能しました。 私は日中にチケットに答えようとしました。 これはすべて、私のライブラリーが実稼働で使用でき、多くのユーザーがそれを使用したことを示しています。
問題は1つだけでした。 私は自分のプロジェクトで使用するのに十分なライブラリを持っていましたが、他の人には使用していませんでした。 彼らは私にそれを開発してほしかったが、私はそれを必要としなかった。 Windowsのサポートが必要なものもあれば、ssl、pg_notify、safari、pthreadsなどが必要なものもありました。 さまざまな機能の実装を要求するオープンチケットは何年もかかっています。
少し前に、ライブラリのユーザーに役立つ製品を再検討することにしました。上記の2つのプロジェクトに加えて、3番目の製品が登場したことを嬉しく思いました。 彼は私のニーズなどを完全に満たしてくれました。
労働者
GitHubで4,500つ星
- 依存関係の欠如
- プロトコル:websocket、http / https、tcp、custom
- タイマーサポート
- コンポーネント統合の反応
- Windowsサポート
最初のリリースは2年前でしたが、何らかの理由で新しいプロジェクトに私のライブラリを使用する人が増えています。 古いプロジェクト(作品-触れないでください)で使用されていることはまだ理解できますが、新しいプロジェクトでは...-私にとっては謎でした。
「php websocket」をグーグルで検索すると、最初のページはHabréに関する私の記事、2ページ目は「Ratchet」です。これは誰かにとって複雑に思えるかもしれません。
さて、この厄介な間違いを修正し、Workermanのようなライブラリの存在についてできるだけ多くの人々に伝え、その使用方法についていくつか例を挙げてみましょう。
githubのプロジェクトのメインページにはすでにいくつかの例があります。 それらのいずれかを検討してください。
WebSocketサーバー
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // Create a Websocket server $ws_worker = new Worker("websocket://0.0.0.0:8000"); // 4 processes $ws_worker->count = 4; // Emitted when new connection come $ws_worker->onConnect = function($connection) { echo "New connection\n"; }; // Emitted when data received $ws_worker->onMessage = function($connection, $data) { // Send hello $data $connection->send('hello ' . $data); }; // Emitted when connection closed $ws_worker->onClose = function($connection) { echo "Connection closed\n"; }; // Run worker Worker::runAll();
tcpサーバー
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // #### create socket and listen 1234 port #### $tcp_worker = new Worker("tcp://0.0.0.0:1234"); // 4 processes $tcp_worker->count = 4; // Emitted when new connection come $tcp_worker->onConnect = function($connection) { echo "New Connection\n"; }; // Emitted when data received $tcp_worker->onMessage = function($connection, $data) { // send data to client $connection->send("hello $data \n"); }; // Emitted when new connection come $tcp_worker->onClose = function($connection) { echo "Connection closed\n"; }; Worker::runAll();
この例を実行するには、workerwanをインストールする
composer require workerman/workerman
サンプルは、
php test.php start
コマンドを使用して起動でき、コンソールに表示されます:
----------------------- WORKERMAN -----------------------------
Workerman version:3.3.6 PHP version:7.0.15-0ubuntu0.16.10.4
------------------------ WORKERS -------------------------------
user worker listen processes status
morozovsk none websocket://0.0.0.0:8000 1 [OK]
----------------------------------------------------------------
すべての労働者チーム:
php test.php start
php test.php start -d-スクリプトを悪魔化します
php test.phpステータス
php test.php stop
php test.php restart
php test.php restart -d
php test.php reload
原則として、最初の例を使用すると、Webソケットでチャットを行うことができ、他の例は必要ありません。 しかし、数年間、基本的に私のライブラリのユーザーは、例のように全員にではなく、PHPコードから選択したユーザーに通知を送信する方法の例が必要であることに気付きました。
例:
- ユーザー#1はユーザー#2の写真が好きなので、ユーザー#2が現在サイトにいる場合、ユーザー#2についてこれに関する通知を送信したいと思います。
- 新しいアナウンスがサイトに表示されたので、モデレーターに通知を送信します。
彼はそれをチェックしました
上記の2つの例から、必要なことを実行する1つをまとめることができます。
1人のユーザーにメッセージを送信する:
server.phpサーバーコード:
クライアントコードclient.html:
サイトsend.phpからメッセージを送信するためのコード:
<?php require_once __DIR__ . '/vendor/autoload.php'; use Workerman\Worker; // $users = []; // ws-, $ws_worker = new Worker("websocket://0.0.0.0:8000"); // , ws- $ws_worker->onWorkerStart = function() use (&$users) { // tcp-, $inner_tcp_worker = new Worker("tcp://127.0.0.1:1234"); // , , // tcp- $inner_tcp_worker->onMessage = function($connection, $data) use (&$users) { $data = json_decode($data); // userId if (isset($users[$data->user])) { $webconnection = $users[$data->user]; $webconnection->send($data->message); } }; $inner_tcp_worker->listen(); }; $ws_worker->onConnect = function($connection) use (&$users) { $connection->onWebSocketConnect = function($connection) use (&$users) { // get-, $users[$_GET['user']] = $connection; // get- cookie, $_COOKIE['PHPSESSID'] }; }; $ws_worker->onClose = function($connection) use(&$users) { // $user = array_search($connection, $users); unset($users[$user]); }; // Run worker Worker::runAll();
クライアントコードclient.html:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <script> ws = new WebSocket("ws://127.0.0.1:8000/?user=tester01"); ws.onmessage = function(evt) {alert(evt.data);}; </script> </head> </html>
サイトsend.phpからメッセージを送信するためのコード:
<?php $localsocket = 'tcp://127.0.0.1:1234'; $user = 'tester01'; $message = 'test'; // tcp- $instance = stream_socket_client($localsocket); // fwrite($instance, json_encode(['user' => $user, 'message' => $message]) . "\n");
公平を期して、ラチェットについても同じ例を書くことにしましたが、3年前のようにドキュメントは役に立ちませんでした。 しかし、 stackoverflowでは、彼らは少し松葉杖を提供しましたが、作業オプション:phpスクリプトからWS接続を介して接続すること。 もちろん、これはstream_socket_clientを使用してtcpソケットに接続し、fwriteを使用してメッセージを送信するほど単純ではありません。 しかし、すでに何か。
さらに、私にとって未解決の質問がありました:ラチェットは複数のワーカーを実行する機能をサポートしていますか? 労働者では、これを行うことができます 。
一般的に、私は自分用にWorkermanライブラリを選択し、私のライブラリのユーザーがそれに切り替えることを推奨しています。 すべての例はgithubにあります。
更新:コメントでは、 swooleを推奨しています 。 私は以前にこのライブラリに出会いましたが、php7をサポートしていないという誤った印象を受け、その後、私の視野から外れました。 しかし、無駄に。 興味深いライブラリ。