スマートリモートを作成する-C#およびXNAのデスクトップクライアント

こんにちは、C#+ XNAを使用してデスクトップクライアントを作成する方法を示します。





このトピックは、私にこの記事を書くきっかけになりました。



自分から少し



私はその記事の第2部を非常に長い時間待っていましたが、待ちませんでした。 著者によると、2番目の記事では、UDPを介してリモートクライアントに画像を送信する実装が必要でした。 その後、私は自分自身で記事の2番目の部分を実装しようとしましたが、常にひどい結果になりました。 GDIの描画が遅いため、プログラムは単にコンピューターCore 2 Duo 2.66 GHz、Nvidia GeForce 9600 GTで停止しました。 さまざまな最適化アルゴリズムを使用しましたが、あまり役に立ちませんでした。そこで、XNAを使用することにしました。



伝送プロトコルの選択



伝送プロトコルTCPを選択したかったのですが、問題は少ないですが、UDPを選択しました。誰もがこのような問題には何とか何とかする方が良いと言っているからです。 答えは簡単です-UDPメッセージは65,507バイトのサイズを超えることはできません。これは非常に不便です。 パッケージの平均サイズは130,000バイト(1366x768の画面の場合)です。このようなパッケージを送信しようとすると、次のようにエラーが発生します。





この問題を解決するには2つの方法があります。

1)松葉杖を作成する

2)構造を作成する



1)私は怠け者なので、松葉杖を選びました。 松葉杖は、大きなメッセージを多くの小さなメッセージに分割し、最初のメッセージに送信されるピースの数を書き込みます。 最初のメッセージを失ったため、プログラムは地獄に行き、画像を正常に接着することができません(画像が壊れている部分がわかりません)ので、松葉杖を呼び出しました。



2)画面を多くの部分に分割し、それらの座標を記憶することができます。 これはすべて構造に保存する必要があります。これは非常に便利です。ところで、このアルゴリズムは将来最適化を行うのに役立ちます。



練習する



簡単なものから始めましょう。 送信者から。 画面のスクリーンショットをリモートコンピューターに送信します。 データをロードし、いくつかの変数を初期化する関数を作成しました。



起動ポイントはRun()関数です。

public void Run() { Load(); //       udpClient = new UdpClient(); Bitmap BackGround = new Bitmap(width, height); Graphics graphics = Graphics.FromImage(BackGround); while (true) { //    graphics.CopyFromScreen(0, 0, 0, 0, new Size(width, height)); //       byte [] bytes = ConvertToByte(BackGround); List<byte[]> lst = CutMsg(bytes); for (int i = 0; i < lst.Count; i++) { //    udpClient.Send(lst[i], lst[i].Length, ipEndPoint); } } }
      
      





まず、Load()データがロードされ、その後変数が宣言されループされます。 ループで、画面イメージを取得し、それをバイト配列に変換し、松葉杖を使用して(メッセージを複数のサブメッセージに分割-CutMsg(バイト))、すべてのパケットを送信します。



Load()関数では興味深いことは何も起こりません。

ip.txtファイルから2行が読み取られます。 最初の行は、データの送信先のIPアドレスです。 2行目は、送信先のポートです。 また、画面の長さと幅の領収書があります。



変換機能

 private byte [] ConvertToByte(Bitmap bmp) { MemoryStream memoryStream = new MemoryStream(); //       Jpeg bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg); return memoryStream.ToArray(); }
      
      







そして、最も興味深いのは松葉杖の実装です。

 private List<byte[]> CutMsg(byte[] bt) { int Lenght = bt.Length; byte[] temp; List<byte[]> msg = new List<byte[]>(); MemoryStream memoryStream = new MemoryStream(); //    2    memoryStream.Write( BitConverter.GetBytes((short)((Lenght / 65500) + 1)), 0, 2); //     memoryStream.Write(bt, 0, bt.Length); memoryStream.Position = 0; //      -   while (Lenght > 0) { temp = new byte[65500]; memoryStream.Read(temp, 0, 65500); msg.Add(temp); Lenght -= 65500; } return msg; }
      
      





データを65500のブロックに分割し(明示的に取得するために数値を減らしました)、バイト配列のリストに書き込み、その後このシートを返します。



受信者コード



すべてが受信者にとってより複雑です。デリゲートとイベントを非同期作業に使用し、コードで退屈させたくないので、主なものを書きます。



非同期データ取得。

 int countErorr = 0; private void AsyncReceiver() { IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 0); while (true) { try { MemoryStream memoryStream = new MemoryStream(); byte[] bytes = udpClient.Receive(ref ep); memoryStream.Write(bytes, 2, bytes.Length - 2); int countMsg = bytes[0] - 1; if (countMsg > 10) throw new Exception("  "); for (int i = 0; i < countMsg; i++) { byte[] bt = udpClient.Receive(ref ep); memoryStream.Write(bt, 0, bt.Length); } GetData(memoryStream.ToArray()); memoryStream.Close(); } catch { countErorr++; } } }
      
      





ループをもう一度見て、最初のパケットを取得し、そこから最初のバイトを読み取ります(将来のメッセージの数がこのバイトに書き込まれます)。メッセージが10を超える場合、明らかに最初のパケットを失ったため、損失カウンターを追加します。そうでなければ、すべてのメッセージを取得します。 GetDataイベントを発生させます(バイト[])。



GetData(byte [])でTexture2Dを取得し、バイト配列から変換します。

 private void Receive_GetData(byte[] Date) { BackGround = ConvertToTexture2D(Date); } private Texture2D ConvertToTexture2D(byte[] bytes) { MemoryStream memoryStream = new MemoryStream(bytes); System.Drawing.Bitmap bmp = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(memoryStream); //    .png,  Texture2D    memoryStream = new MemoryStream(); bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); //    Texture2D return Texture2D.FromStream(GraphicsDevice, memoryStream); }
      
      







記事の最後でプロジェクト全体をダウンロードできますので、私が何かを書いていなくてもがっかりしないでください。



まとめと結論



その結果、「送信者」と「受信者」が同時に開始されると、再帰と大量の損失がコンピューターで発生し(30-90の損失)、「送信者」が私のコンピューターと「受信者」の親のコンピューターで起動されると、損失は最小(10- 15の損失)。 両方のコンピューター(親と私のコンピューター)は、54 Mbpsチャネルで同じWi-Fiネットワークに接続されています。 pingがあります(約250ミリ秒)-TeamViewerのpingを思い出させます。 最適化を追加して松葉杖を交換すると、画像を送信するための優れたプログラムが得られます。



再帰





両親のコンピューター(私のコンピューターから彼らに画像を転送する)





損失は​​どのように見えますか?





次の記事では、プログラムを完了するか、リモートで制御する機能を追加し、場合によっては最適化することもします。



プロジェクトをダウンロードする

受信機をダウンロード

送信者のダウンロード(画像の送信)



PS github.com/Luchanso/remote-desktop githubでソースコードをリロードしました



All Articles