トランセンドライブラリ4:はじめに

C ++でネットワークを操作するのは、1、2、3です。

network n = OpenNetwork(); connection c = n.OpenConnection("habrahabr.ru", 80); html_request h("GET", "/"); c << h; c.WaitForMessage(); n.Response(); std::cout << c;
      
      









こんにちは、カブラヴィテス様、今日は過去4年間の私の仕事についてお話ししたいと思います。 私の創造について、私の人生について。 それは、ネットワークを操作するための多機能ライブラリ、その歴史とその作成理由、解決すべきタスク、内部構造についてです。



すぐに予約をしたいのですが、私の作品は自転車かもしれませんが、作成時でも、新しいバージョンへの移行時でも、満足できるアナログは見つかりませんでした。



物語



開始する


すべては2008年の夏に始まりました。 winsockを使用して、最初のサーバーを作成しようとしました。 本当に明確なものは何もなかったので、先生は重要ではありませんでした

また、不便なAPIに非常に腹を立て、すぐにすべてをカプセル化することを望みました。 私はその時c ++を知りませんでした、そして最初のバージョンは関数の名前を変更するだけでした(今は失われています)。



ますますネイティブのwinsockスキームから離れ、コミュニケーションをより透明にしました。 (たとえば、connect関数を呼び出すと、ソケットがすぐに作成され、dns要求が行われ、接続が開かれました)。 徐々に便利になり、ゲームを作ろうと決心しました。



古代の伝説


TL2バージョンの前は、大幅な改善は行われていなかったため、300行のコードを禁止しています。

実際のタスクの出現により、1つの接続(チャット、テクスチャ、音楽)で複数のデータを転送するという問題が発生しました。 進歩自体が始まったのはこのことです。 6か月の間にこの問題を解決し、最適なパケット分割、サービスメッセージの形式を選択し、テストを行いました。 その結果、ライブラリは最大255個の「メッセージ」の同時送信をサポートし、それぞれ最大4ギガバイトのサイズで、タスクにうまく対処しました。

残念ながら、スタッフリーク、利他主義のため、ゲームを書いたことはありません。 はい、そして競合他社が登場しました。 したがって、将来のバージョンの開発に休むことができました。



TL4


次の繰り返しは、C ++への移行と新しい標準の追加、新しいチップの使用、新しい機能でした。

ライブラリは、サーバーとクライアントの2つのモードで同時に完全に動作するようになり、プロキシまたはp2pタスクを解決できます。 最大メッセージサイズは無限に増加し、同時に送信されるメッセージの最大数は最大2 ^ 32です(255はアクティブに送信されます)。 自動再接続機能が追加され、メッセージの送信が優先されました。

ライブラリは非ブロッキングソケットで非同期になり、メインスレッドの負荷を軽減しました。 (たとえば、デフォルトでは、接続を開くにはTL2で443ミリ秒かかり、この数はTL4で17ミリ秒に短縮されました)。

暗号化、圧縮などが追加され、リストは長期間継続できます。



解決すべき主なタスク



ライブラリは、プラットフォームに関係なく、次のことを実行できます。

クライアントに-接続を開き、任意のソース(ファイル、配列、その他の接続)からデータセットを転送し、接続が何回中断されてもデータが配信されることを確認します。

サーバーはポートをリッスンする必要があり、接続数、各接続のトラフィック、オンライン時間、平均速度などに関する情報を常に直感的に把握できます。



例「PROXY」



 #include <tl4/def.h> using namespace ax::tl4; bool proxy( connection &c, message &m ) { std::string s; s << m; //   host:pass,   connection nc = c.GetNetwork().OpenConnection(s); nc << s; nc << c; nc >> c; return true; } void main() { network n = OpenNetwork(); port p = n.OpenPort(8080); p.NonTL4Compatible(true); p.OnOpenConnection(proxy); while (1) n.Response(); }
      
      





もちろん、例はエラー処理なしでシミュレートされ、実際に曲線(メッセージをstd ::文字列に変換しようとすると、プログラムは\ 0が到着するかタイムアウトによってブロックされます)が、本質は明らかです。



特徴







一箇所のプロトコル


これは、コードを複製せずにクライアントサーバーアプリケーションを開発できる非常に便利な機能です。

小さな紹介。 各オブジェクトおよび各パッケージに対して、ハンドラーのキューが呼び出されます(明らかな理由でオンザフライで変更することはできません)。 ハンドラーには、エンコードとデコードの2つのメソッドがあります。 したがって、暗号化/復号化コード、圧縮/解凍コードは常に1つの場所にあります。 これにより、ハンドラーの正当性を確認できます-Testメソッドを呼び出すだけで、暗号化および復号化後に元のバージョンが取得されたランダムまたは提供されたデータを確認できます。

プロトコルにも同じことが言えます-プロトコル全体として、オブジェクトをメッセージに、メッセージをオブジェクトに変換できるのと同じメソッドがあります。



仕組み



ストリーム


プログラミングの世界のすべては、シーケンスを通して表現できます。 配列、文字列、ファイルはすべてバイトのシーケンスです。 変数とインバウンドアウトバウンド接続についても。

ストリームクラスシステムは、ストリームの物理ソースから抽象化し、情報で実際に発生する変換から抽象化するために作成されました。

stl :: streamに似ていますが、いくつか改善されています。



パイプ


単純なタスクを想像してください。ディスクから画像を転送したいのです。 これを行うには、ダウンロードしてbmp-> jpgに変換し、暗号化する必要があります。 これは、ハンドラーを次々に配置し、これが原子変換であると言うことで簡単に実行できます(給水を伴うアナロジー-パイプが突き合わせて行きます)。

 pipe *ImageTransferPipe( std::string filename ) { pipe_constructor c; c.add(new BMP2JPG()); c.add(new BlowFishCrypt()); pipe p(c); return p.GetScheme().Source(new read_file_stream(filename)); }
      
      





最初はあまり明確で便利ではないようですが、APIを読んだ後は簡単になります。



すぐに使用可能な暗号化


ご想像のとおり、接続を作成する場合、論理的な機能は1つだけです。

 connection::SetHandler( pipe * )
      
      





送信中の各バイトはこのハンドラーを通過し、受信中の各バイトは対応するプロセッサーも通過します(パイプ:: GetInverseScheme)。



複数のオブジェクトを一度に転送する


このアイデアは非常にシンプルで、必要な人とまだやっていない人に役立つと思います。

送信用のキュー内のすべてのオブジェクトは、255バイトずつ細断され、これらのブロックによって送信されます。 ブロックにはオブジェクトIDが提供されます。 オブジェクトは周期的に送信されます-最初、2番目、3番目、1番目、2番目、3番目。

ブロックは常に255バイトであり、サイズは提供されないことに注意してください。 突然ブロックが小さくなった場合、これはサービスメッセージによって調整されます。

オブジェクトの次の部分が突然「準備ができていない」(データなし)場合、準備ができた1つと引き換えに、非アクティブなキューに移動します。 これはすべて、システムメッセージによって規制されています。



システムメッセージ


それらにはいくつかの機能があります。 送信側は、アクティブ/非アクティブの回転を報告し、オブジェクトの終わりが近づいていることを警告し、オブジェクトの追加、「低レベル」例外の送信、オブジェクトのパイプ形式の送信を報告し、最も興味深いのは同期です。

マシン同期


正しく動作させるには、両端でオンにする必要があります。 このタスクのために、オブジェクトの優先度を認識する必要がありました。これらのサービスメッセージは、作成時にキューに追加する必要があります。

ホストはタイムスタンプをミリ秒で交換し、pingを受信します。 平均値を設定した後、彼らもそれを交換し始めます。 その結果、両方のマシンに応答時間があります。

最も興味深い部分は、サーバーソリューションから始まります。 pingが数百を超えるプレイヤーは私を理解するでしょう。 敵は数ミリ秒前に何か重要なことを知っているでしょう、そしてそれだけです。

次に、イベントがすべてのマシンに同時に到着するゲームを想像してください。これは単純に行われます。 同時メッセージを送信する場合、接続は遅延の順にソートされ、実際のデータは、接続の安定性を考慮して、推定到着時間が等しくなるように送信されます(有線ソリューションのエラーは10ミリ秒未満)。



なぜこの投稿なのか?



実際には、ライブラリは完全ではありません。 たとえば、予定されているすべての接続パラメーターがサポートされているわけではありません。暗号化アルゴリズムをそのまま使用したり、チェックサムを追加したりします。 一般的に、作業はまだ進行中です。

ここでは、宣伝するために表示されませんでしたが、アナログがあるかどうか確認し(人々がそれを持っている方法確認するためにいくつかのアイデアを盗みたい)、誰かがそれを必要とするなら(市場に行くのが理にかなっています)システム。



謝罪


プレゼンテーションの仕方、エラー、不正確さについておaび申し上げます。 カルマが低いため、「I am PR」というタグを追加できませんでした。 そして確かに無駄に、私はおそらくそれを行います。



UPD: 続き



All Articles