すべての人に良い一日を!
そして、今後の休日に!
私のリポジトリには、この記事の最後にあるコードが含まれています。
おそらく、すべてを再び書き直したという事実から始めますが、これは構造に影響しませんでした。 過去に多くの変更を行いましたが(サーバーとクライアントの両方で)、これまでにいくつかの側面が残っています(それらを作成してプレーヤーの初期位置を配置するプログラムを作成しませんでした(これまではすべて手動))。すぐに来ます。
批判を聞いて、このプロジェクトの分析で興味深い記事を書いてみます。
第1章:「作業クライアント」
いい名前ですね しかし、その背後にはクライアントの意味があります。 小さなスケルトンを作りたかったのですが、時間が経つにつれて試験が行われ、リファクタリングが少し難しくなりました。
(CODEによる)クライアントの解析を開始する前に、クライアントサーバーがどのように相互作用するかを説明する必要があります。
1.クライアントが言います:「サーバーよ、あなたのところに来ました!」
2.サーバーは彼に応答します:「クライアント、ここに壁とプレイヤーの座標があります。」
3.クライアントは再び「今から話します」と言います。
そして、それらの間で発生しました... TCPソケット上の通信。
主なメソッドが変更され、驚きました->別の名前空間とクラスから始めます。 将来、これをやり直します(すべてを別のファイルに分割することを約束しましたが、休日や試験に関連して困難であることが判明したため、別の名前空間に頼りました)。
上記のスキームで実際に機能する主な変数は、サーバーのポートとアドレスです。
クライアントは条件付きで2つのグループに分割できます。
まず、これはサービスグループです。 計算を実行し、サーバーから当社にコンソールにメッセージを出力する関数。
2番目に、これは相互作用アルゴリズムのグループです(上で示したように)。
サービスグループとすべてすべて
主に最初の名前空間にあるこのグループには、次のようなクラス/構造が含まれます。
// "" public struct WallState // "" public struct ShotState // public class Position // public struct PlayerState
私はすでにそれらを以前の投稿でレビューしましたが、その中の何も変更しませんでした(いくつかのフィールドを除き、それらを公開しました)。
名前を変更しても、メソッドの意味は変わりません-座標に応じてタンクを印刷します:
static void PrintCoordinate(int x, int y, int dir, int id)
そして、私たちの主な方法:
static void Work()
このメソッドは素晴らしい仕事をします-押されたキーを処理し、他のメソッド(構造内にある)を通してデータを収集し、それらをサーバーへの送信メソッドに送信します。
ネットワークグループ
サーバーと通信するメソッドのグループ。
ここにあります:
// static void Eventlistener() // static void Connect() // static void Disconnect() // static void MessageToServer(string data)
最初のメソッド(Eventlistener())は2番目のスレッドで開始され、サーバーをリッスンします。一方、メインスレッドは押されたキーを処理し、変更されたデータをサーバーに送信します(MessageToServer()メソッドを使用)。 残りのメソッドは、クライアントの起動/シャットダウン時にのみ使用されます。
第2章:自転車サーバー
サーバー(その主要部分)はマルチスレッドモードで動作します。 複数のストリームでのマルチスレッド読み取りおよび送信。
興味深い事実は、最大ワークロード(6人と想定)で、同時に起動されるスレッド(読み取りと送信の両方)の数は読み取りで6、6 * 6 = 36-全員への同時送信(合計-42)であり、それは論理的ですが、実際には、クライアントは1秒あたり2〜4アクション(pingを考慮に入れる)を実行できます。これにより、スレッド数が(送信によって)2〜4倍になります。
つまり、次の公式が得られます。Count+ Count * i +1。Countはユーザー数、iは同時に実行されるアクションの数、+ 1はメインストリームを考慮するためです。
なぜマルチスレッド読み取りですか? 私にとって非常に便利で、すべてを異なるストリームに分割し、それらからの情報を処理してクライアントに送信したり、別のボーナスを送信したりするのがはるかに簡単です-クライアントとの接続を切断することはありません。これは非常に重要ですデータはオフになります(次の各送信に次のポートが使用されます)。
ストリーム間の接続は、標準ライブラリからstd :: sync :: mpsc :: channel()関数を呼び出すことで作成されるTransmitter-Receiverタプルによって実装されます。
use std::sync::mpsc; let (sender, receiver) = mpsc::channel();
ただし、この方法には制限があります。トランスミッターがメッセージをレシーバーに送信(発言)しないことは不可能だからです。 なぜなら コンパイラーは、メッセージの受け渡しにどのタイプが使用されているかを知りません。
なぜ最初のストリームが必要なのか、なぜ送信機と受信機が必要なのか? これはスレッド並列化であるため、メインスレッドはすべての宛先にデータを送信するためのスレッドを作成します。
つまり、スキームを取得します。

ボックスが別々のストリームであり、一方から他方への矢印がトランスミッタの.send()メソッドです(つまり、レシーバにデータを送信します)。
しかし、データを受信するストリームには多くのストリームがあります(上記の式で見たように)、完全なスキームは次のようになります。

このすべての解析を始めましょう。 ネットワークインタラクションを開始する前に、ファイルからデータを読み取る必要があります。何かを送信する必要があり、カードをサーバーに縫い付けないでください(これらのカードを作成するプログラムを作成するため)。
lib.rs(mod Text)の関数を使用してファイルを読み取り、処理します。
サーバーの小さなスキーム:

そして、ここにコードがあります:
サーバーを手動で作成できる機能(net_serverモジュールから) fn start_game_handle(){ let mut i:usize = 0; println!(". - :"); let mut number_player = String::new();
そして、メインから呼び出します:
fn main() { net_server::net_server::start_game_handle(); }
これが自転車の仕組みです。将来、この記事(および私のリポジトリ)にc#でサーバーを追加します。
結論!
私が失敗したこと:
1. WinFormバージョン。
2.レベルを視覚的に作成するためのプログラム。
3.可能な最小プレイヤー数に達したときのn秒での試合の開始。
私のリポジトリ最初の記事第二の記事あなたの願いと訂正を待って、批判と多くのあなたに最高に感謝します!