PHPのWebsocket。 Webソケットサーバーの選択

むかしむかし、ハブに関する記事を公開しました。Webソケットサーバーをゼロから作成する方法です。 記事は図書館になりました 。 数ヶ月間、私はその開発に携わり、さらに数年-サポートとバグ修正を行いました。 yii2と統合モジュールを作成しました。 一部の愛好家は、laravelとの統合を書きました。 私のライブラリはphp7と互換性があります。 最近、私はそのさらなるサポートを放棄することを決定しました(以下の理由)ので、私はそのユーザーが別のライブラリに切り替えるのを助けたいです。







Webソケットサーバーの作成を開始する前に、既製の製品から選択しましたが、当時はphpdaemonとratchetの2つしかありませんでした。



phpdaemon



GitHubで1,400つ星





ラチェット



GitHubで3,600つ星





これらのライブラリは非常に巨大であり、同時に私の内部要件を満たしていませんでした。





すべてのユーザー間のインタラクションを0.05秒ごとに計算するために、Webソケットでゲーム作成するタイマーが必要でした。



最後に、私は自分でライブラリを作成し、 githubでコミュニティと共有しました。 彼はいくつかのデモを作成しました(ゲームの「タンク」を含む)。 node.jsからライブラリにサードパーティのゲームを(作成者の許可を得て)書き直しました。 負荷テストを行いました。 デモは再起動なしで何年も機能しました。 私は日中にチケットに答えようとしました。 これはすべて、私のライブラリーが実稼働で使用でき、多くのユーザーがそれを使用したことを示しています。



問題は1つだけでした。 私は自分のプロジェクトで使用するのに十分なライブラリを持っていましたが、他の人には使用していませんでした。 彼らは私にそれを開発してほしかったが、私はそれを必要としなかった。 Windowsのサポートが必要なものもあれば、ssl、pg_notify、safari、pthreadsなどが必要なものもありました。 さまざまな機能の実装を要求するオープンチケットは何年もかかっています。



少し前に、ライブラリのユーザーに役立つ製品を再検討することにしました。上記の2つのプロジェクトに加えて、3番目の製品が登場したことを嬉しく思いました。 彼は私のニーズなどを完全に満たしてくれました。



労働者



GitHubで4,500つ星





最初のリリースは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コードから選択したユーザーに通知を送信する方法の例が必要であることに気付きました。



例:





上記の2つの例から、必要なことを実行する1つをまとめることができます。



1人のユーザーにメッセージを送信する:
server.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をサポートしていないという誤った印象を受け、その後、私の視野から外れました。 しかし、無駄に。 興味深いライブラリ。



All Articles