前の記事では、swoole の基本的な使用方法について説明しました。ここでは、数行の基本的なステートメントを使用して、より複雑な論理演算を実装できます。
まず、ビジネス シナリオについて説明します。現在のアプリケーションのほとんどは、サーバー + インターフェイス + クライアントの形式で動作を調整します。この利点は、どの端末であってもサーバーと完全に互換性があることです。これにより、MVC のさまざまな部分の真の分離を簡単に実現できるようになります。ただし、プログラムの使いやすさを向上させるにはまだ長い道のりがあります。誰もが遭遇するであろう問題の 1 つは、リアルタイムのデータ更新の問題です。たとえば、ユーザーが携帯電話で追加操作を実行した場合、他の端末もデータの変更をタイムリーに表示する必要があります。携帯電話では、プッシュ アップデートを受信する際に、プッシュの内容に応じて対応するインターフェイスを要求するだけで、さまざまなプッシュ サービスがニーズに完全に対応できるため、これは比較的簡単に処理できます。しかし、PC ではそうではありません。ブラウザと http プロトコルの特殊な特性により、別の方法を見つける必要があります。
人生において誰もが遭遇するであろう場面を考えてみましょう。ある週末、ガールフレンドと映画に行きたいと思い、PC でショーの番号と座席を見つけました。注文して支払いをしようとしたとき、システムは座席が販売されたことを通知するメッセージを表示するため、座席選択ページに戻って新たに選択する必要があります。製品エクスペリエンスを改善すると、他のユーザーが特定の座席を購入すると、ブラウザーはその座席をすぐに販売済みとしてマークするため、何度も行き来する必要がなくなり、時間を節約できます。
** 上記のシナリオについて、システム間の対話のフローチャートを次に示します。 **
次の行は、他のユーザーも同じデータを操作していることを示しています。 ① (緑色) が結果を返すと、Web サーバーは現在のユーザーと Redis キュー サービス (① 黄色) に同時に通知します。これは、WebSocket サービスが Redis をリアルタイムで監視しているため、データが変更されると WebSocket がサービスはすぐにそれを感知します。このとき、ブラウザと確立した長時間の接続を介して通信し、データが更新されリロードされたことを通知します。
もう 1 つの方法は、① (緑) が結果を返すときに Redis キューに通知せず、データが変更されたことを WebSocket サービスと直接通信し、WebSocket サービスがブラウザ クライアントにリロードするように通知することです。この解決策は比較的単純であり、一部の操作をカプセル化するには swoole の方が便利であるため、ここではこのメソッドが使用されます
ws.onopen = function(){ console.log("socket连接已打开"); $.post('/mercha/merchant/find',function(d){ //从web服务端获取注册id d = $.parseJSON(d); ws.send("merchantId_"+d.data.id); })};
$server->on('Message', function ($serv, $frame) { if(stripos($frame->data,'merchantId_') !== false){ $fd = $redis->get($frame->data); if($fd != null){ $fd = json_decode($fd,true); } //这里的$frame->fd是指当前的websocket连接id,swoole会通过此id发送给对应的接收方,可以理解为手机号码 $fd[$frame->fd] = $frame->fd; $fd = json_encode($fd); $redis->set($frame->data,$fd); }});
$server->on('Request', function ($req, $respone) { if(isset($req->get['merchantId'])){ global $server; global $redis; $merchantId = $req->get['merchantId']; $fd = $redis->get("merchantId_".$merchantId); if($fd != null){ $fd = json_decode($fd,true); } $err = 0; if(is_array($fd)){ foreach($fd as $f){ $res = @$server->push($f, "refresh"); if($res === false){ unset($fd[$f]); $err++; } } if($err){ $fd = json_encode($fd); $redis->set("merchantId_".$merchantId,$fd); } } } $respone->end("success");});
* * 強調する必要があるのは、http リクエストを監視するサーバーにはプッシュ メソッドがないということです。そのため、ここでは websocket の $server を使用して、グローバル変数を通じてクライアントにデータを送信します**
上記は問題の解決策です。これは記事の最後に、WebSocket のサーバーのソース コードを添付します。多くのビジネスがあるため、統合します。実行するには、まず swoole 拡張機能をインストールする必要があります。インストール方法は以前の記事で説明していますので、参考までに説明します。
上記の Redis を使用する他の方法も非常に優れており、以前の Redis パブリッシュおよびサブスクライブ モデルの使用でも、基本的には目的の効果を達成できます。しかし、途中で問題が発生し、redis サブスクライブが数十秒間実行されると、RedisException がスローされます。その理由は、PHP の Redis ライブラリで使用されるサブスクライブは PHP の組み込みソケットを使用し、php.ini がデフォルトでソケット タイムアウトを 60 秒に設定するためです。そのため、default_socket_timeout 構成項目を見つけて、時間をより長い時間に変更するだけで済みます。 。または、ini_set('default_socket_timeout', -1);
WebSocket サーバーのソース コード
を追加します