
簡単に説明すると、nginxはwebsocketに弾丸を付ける方法を知らず、リクエストごとにphpが機能します。 Webソケットを開いたままにして、データが到着したらphpに接続し(同じfastcgiを介して)、応答を送信するレイヤーが必要です。
更新:これは、nodejsに比べても、はるかに遅いphpソリューションに関するものではありません。
判明したように、このトピックは新しいものではなく、ソースコードは2014年から継続していますが、それでも、ここで説明するトリックに関する情報は非常に少ないものです。 「
websockets php 」をグーグルで
検索できます。 このトピックは、見つかった実装例(2つ、より正確には)が機能しないという事実によってさらに悪化しています。
ここで、私は内部のどこかで、何であるかを知っていました。 私は長い間、このミドルウェアをNginx内に入れて、異なるかなり遅いphpライブラリ(
1と
2 )を使用せず、シングルスレッドのnodejsをバイパスしたくないと思っていました。 そして、私は多くの(そして可能な限り)Webソケットが欲しいので、レイヤーの追加コストはより少なくなりました。 そのため、nodejsを使用して多数のマシンを作成しないように(将来、通常は高負荷でこれを行います)、Nginxが提供する一部の拡張機能をlua + restyの形式で使用します。 Nginx + luaは
nginx-extrasパッケージからインストールすることも、自分でビルドすることもできます。 Restyからは、
websocketのみが必要です。 libディレクトリの内容をパスのどこかにダウンロードしてドロップします(
/ home / username / lib / lua / libがありますが、良い方法では
/ usr / local / share / luaにあります )。
デフォルトでは、nginx + websocketsは次のように機能します。
- クライアントはnginxに接続します
- Nginxはアップストリームへのプロキシ/ websocketを提供する別のサーバー(nodejs + sockets.ioに基づくミドルサーバーなど)でプロキシストリームを開きます。
- Middle Serverサーバーは、epollなどのイベントリスナーにソケット接続をスローし、データを待機します。
- データを受信すると、Middle Serverサーバーは、次にphpでFastcgi接続を開き、待機して回答を取得します。 ソケットに送信します。 データを待っているソケットを再び返します。
- 特別なWebSocketクロージャーフレームが届くまで、円で囲みます。
リソースのオーバーヘッドとこのソリューションのシングルスレッドを除き、すべてが単純です。
提案されたスキームでは、MiddleServerはnginx内のミドルウェアに変わります。 さらに、Fastcgiの期待はなく、すべての作業は同じepollによって行われ、nginxはオープンソケットを信頼しますが、一方で、nginx'aスレッドは他のことを行うことができます。 このスキームにより、ストリームに散在する多数のWebソケットを同時に操作できます。
ここでは、他のホスティング設定なしで、タスクに関連する単純化されたコードのみを提供します。 私はすべての見出しを不必要なものとして修正しようとしませんでした。
lua_package_path "/home/username/lib/lua/lib/?.lua;;"; server {
そして、ws.luaコード:
local server = require "resty.websocket.server" local wb, err = server:new{
他に何ができますか? 速度を測定し、nodejsと比較します:)そして、lua内のRedis、MySQL、Postgresでリクエストを行うことができます...
既知の問題:Webソケット上のデータパケットの最大サイズは65 KBです。 必要に応じて、フレームにブレークを追加できます。 プロトコルは複雑ではありません。
テストhtml(ws.html):
ここにHTML <!DOCTYPE> <html> <head> <meta charset="utf-8" /> <script type="text/javascript"> "use strict"; let socket; function tryWebSocket() { socket = new WebSocket("ws://try6.local/ws/"); socket.onopen = function() { console.log(" ."); }; socket.onclose = function(event) { if (event.wasClean) { console.log(' '); } else { console.log(' '); </script> </head> <body onLoad="tryWebSocket(event);return false;"> <form onsubmit="tryWSSend(event); return false;"> <button onclick="tryWebSocket(event); return false;">Try WebSocket</button> <fieldset> Message: <input value="Test message 4444" type="text" size="10" id="msg"/><input type="submit"/> </fieldset> <fieldset> <button onclick="closeWebSocket(event); return false;">Close Websocket</button><br/> </fieldset> </form> </body> </html>
テストphp(mywebsockethandler.php):
ここにPHP <?php header("Content-Type: application/json; charset=utf-8"); echo json_encode(["status"=>"ok","response"=>"php websocket json @ ".time(), "payload"=>[$_REQUEST,$_SERVER]]); exit;
LuaにFastCGIを使用するには、
別の Resty拡張機能をインストールします。