言語: Lua ロジック接着剤を使用した C++。
コードは、適切なバージョンの LuaJIT が使用されていることを前提として、Ubuntu x86、Ubuntu x86_64、および Gentoo x86_64 でコンパイルおよび実行できるようにテストされています。 「整数」を適切にサポートし、倍精度のみをサポートする Lua からの自動変換を維持するために、整数の後に .0 による浮動小数点数の強制フォーマットを削除するための libjansson への変更。
libjansson と google-glog が手動でビルドされている場合、Ubuntu 12.04 LTS x86_64 でもコンパイルされます。
ルアジット
リベブ
evhttpクライアント
グーグルブログ
google-perftools (tcmalloc) -ソースと Makefile に若干の変更を加えたオプション
リブヤンソン
雇われ者
libicu - ローカルパッケージマネージャーを参照
curl - ローカル パッケージ マネージャーを参照
boost -侵入的なポインタを独自のものに置き換える場合のオプション。
インストール フォルダーを反映するために src/Makefile を変更する必要がある可能性があります。より堅牢なビルド システムは歓迎されますが、プロジェクトが作成された時点では必須ではありませんでした。 (CMake?)
私 (@zwagoth) はここで何かを学びました: 執筆時には必ずコメントをすることです。これを補うために、理解を助けるためにプログラムの基本構造を文書化します。
コードベースが混乱していて申し訳ありません。これは、規模や複雑さを問わず、私にとって初めての C++ プロジェクトの 1 つでもありました。
プロトコル メッセージ、RTB メッセージ、および接続や切断などのさまざまな基本イベント コールバックのメッセージ処理のためのほぼすべてのコア ロジックが含まれています。
このファイルには、処理するイベントにちなんで名付けられた匿名関数のテーブルが含まれています。このファイルには状態は保存されず、論理保存領域のみとみなされます。このファイルの基本設計は、Lua に重労働を強いることなくグルー ロジックを許可し、C++ への関数呼び出しが増える代わりに Lua に送受信されるデータ量を最小限に抑えることです。
グローバル ファイル名前空間には、入力しやすいように短い名前が付けられた 4 つのテーブルが挿入されています。
u
: 接続/キャラクター(ユーザー)関数
s
: サーバー/グローバル状態関数
c
: チャネル状態関数
const
: エラー ID と定数値
プロトコル コールバック関数は、コマンドが関連付けられている接続と、提供された json 引数のテーブル コピーの 2 つのパラメーターを受け入れます。
接続は不透明な数値なので、いかなる方法でも変更しないでください。接続の値を変更することは安全ではありません。あなたは警告を受けました。
チャット デーモンの起動および操作中に使用される構成変数の lua ファイル。
最小限のフラッシュ ポリシー サーバー。 Flash をサポートする必要がある場合は、これを実行します。ニーズに合わせてインライン ポリシーをカスタマイズします。
プログラムのエントリポイント。バックグラウンド スレッドとカールの初期化を処理します。
あまりにも多くのことを行います。コード フローはServer::run()
から始まります。
接続の流れは以下の通りです。
listenCallback handshakeCallback connectionWriteCallback connectionReadCallback connectionwriteCallback
listenCallback
接続ごとにイベント ハンドラーを設定し、フローを渡します...
handshakeCallback
: WebSocket ハンドシェイクの読み取りを処理します。
connectionWriteCallback
接続に書き込む準備ができたときを処理し、接続に書き込む項目がキューにあるときに有効になります。バッファリングを処理します。
connectionReadCallback
、ハンドシェイク フェーズが終了すると、すべての読み取りイベントを処理します。すべてのプロトコル解析はここで行われ、コマンドがディスパッチされてこの関数内から実行されます。
pingCallback
クライアントへの ping イベントの送信を処理します。プロトコルが変更された場合、これは最初に行うべきことの 1 つです。
connectionTimerCallback
は定期的に起動され、接続が切断されているかどうかを確認してクリーンアップします。
runLuaEvent
イモリの魔法です。また、各コマンドで魔法が起こる場所も説明します。ここで、各コマンドが C++ コードから Lua コードに移行します。すべての Lua 状態と、Lua が無限ループに巻き込まれないようにするためのコールバックを処理します。 Lua 内部から印刷エラーを処理します。
このファイルには、チャネル、接続、禁止、モデレーションに関連するすべての状態データが保存されます。
キャラクタ名は、ログイン サーバーがキャラクタの存在を検証するまで不明であり、名前で検索できる文字のプールから除外されるため、接続は識別されたものと識別されていないものに分割されます。
ディスクへの状態の保存と復元を処理します。
ログイン要求と応答を処理し、それらをメイン スレッドに返すバックグラウンド スレッドとして実行されます。
シリアル化されたログイン システム。グローバル ログイン キューを使用します。これはかなり改善される可能性があります。
curl_multi への変換は良いことですが、libev との楽しい対話や多くのブラインド ポーリングが必要になります。スレッド化のため、キューはアクセスする前にロックする必要があります。
基本的なチャネル クラス。チャネルの存続期間中、チャネルに関する状態データを維持します。チャネルに関連するすべての低レベルのアクションは、Lua のフックを通じてこのファイル内で発生します。通常は、インスタンスの有効期間を管理するために侵入型ポインタでラップされます。
ここで、JSON からのチャネルのシリアル化と逆シリアル化が行われます。
すべての接続ネットワークを処理し、Lua 状態をデバッグします。
キンクリスト、ステータス、ステータスメッセージ、性別を維持します。
無視リストと友達リストを維持します。
接続スロットルごとにハンドルします。
ここで出力データのバッファリングが行われます。
通常、インスタンスの有効期間を管理するために煩わしいポインタを使用して渡されます。
どのチャネルが参加しているかの内部リストを維持します。これは、実際のチャネル ユーザー リストと同期しておく必要があります。
このファイルは、カスタマイズ可能であることよりも実際の速度を必要とするいくつかの機能のために予約されています。ログイン ( IDN
) コマンドを処理します。デバッグ ( ZZZ
) コマンドを処理します。検索 ( FKS
) コマンドを処理します。
Lua ファイルのs
カテゴリに分類されるすべての Lua ラッパー コマンド。
Lua ファイルのu
カテゴリに分類されるすべての Lua ラッパー コマンド。
Lua ファイルのc
カテゴリに分類されるすべての Lua ラッパー コマンド。
Lua ファイルのconst
カテゴリに分類されるすべての Lua ラッパー値。
エラーメッセージと定義。
定義されたマクロをエラーと型のチェックに使用してください。これは、誤った型が軽量データとして関数に予期せず渡された場合にクラッシュを防ぐ唯一の方法です。
Lua スタックのバランスが取れていることを確認してください。これが真実であることを確認するために一生懸命努力しましたが、間違いは簡単に起こります。
テーブルを Lua コードに戻すことは避けてください。テーブルは構築にコストがかかり、多くの場合使用期間が短いためです。最善の判断を行って、関数呼び出しのコストとテーブル構築のコストのバランスをとってください。
文字列を不必要に Lua に渡さないようにします。メモリのコピーによりコストがかかる場合があります。
lua がネイティブ機能として複数の戻り値を受け入れることを悪用します。上の 2 つのメモを参照してください。
プッシュ専用の Redis スレッドを処理します。 Redis コマンドとその戻り値の小さなラッパーです。
入力キューを使用してコマンドを受信します。コマンドは定期的に実行されるため、信頼性は保証されません。無効にすることができ、無効にすると入力は無視されます。
gdb は、このアプリケーションのデバッグに適しています。 tcmalloc と LuaJIT の JIT セクションを無効にすると、クラッシュのデバッグに非常に役立ちます (tcmalloc は、いくつかの軽度のヒープ破損を隠すことができます)。
tcmalloc のメモリ プロファイリング ツールは非常に優れています。使用方法の詳細については、tcmalloc のドキュメントを参照してください。