"パラメータが無効です" TCP 画面共有プログラム [C#]


これはよく聞かれる質問だと思いますが、何日も調査を続けてきましたが、役立つ方法が見つかりませんでした。

画面共有プログラムを開発しており、TCP を使用してデスクトップのスクリーンショットをネットワーク ストリーム経由で送信しています。 UDP を使用してみましたが、メッセージ サイズの制限が 65,507 バイトであり、1 つのメッセージのバイト数がはるかに多いため、TCP を使用していることが後でわかりました。

プログラムを実行すると、いくつかの画像が取得され、バイトサイズが大きくなると、バイトを画像に変換するときにスローされます

スローされた例外:

'System.ArgumentException' in System.Drawing.dll
System.ArgumentException: Parameter is not valid.

私がどこでも読んだ限り、ネットワークストリームはサーバーから送信されたすべてのバイトを読み取るのに時間がかかり、ネットワークストリームが読み取りを完了する前にサーバーが別のデータを送信すると、バイト配列のデータが不十分になり、エラーがスローされます. Thread.Sleep(milliseconds) も試しましたが、待機時間を予測できず、プロセスが大幅に遅くなります。

ネットワークストリームの書き込みを待って、ネットワークストリームが送信されたすべてのバイトを読み取り、送信と待機を継続できるようにする方法はありますか?クライアントのピクチャボックスで結合する画像のセットがあるため、これは高速である必要があります。

コード:

サーバ

C#
private void receiveScreenShare()
    {
        TcpListener list = new TcpListener(IPAddress.Parse("192.168.0.102"), 4567);
        list.Start();
        TcpClient client = list.AcceptTcpClient();
        NetworkStream streamScreenShare = client.GetStream();
        while (true)
        {
            try
            {
                byte[] bytes = new byte[1000000];
                streamScreenShare.Read(bytes, 0, bytes.Length);
                ImageConverter convertData = new ImageConverter();
                Image image = (Image)convertData.ConvertFrom(bytes); //Here is the error
                pictureBox1.Image = image;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }

クライアント

C#
byte[] b1 = null;
    private void sendScreen()
    {
        try
        {
            TcpClient client = new TcpClient("192.168.0.102", 4567);
            while (true)
            {
                NetworkStream streamScreen = client.GetStream();
                //Get Screenshot
                Bitmap bm = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                Graphics g = Graphics.FromImage(bm);
                g.CopyFromScreen(0, 0, 0, 0, bm.Size);
                //Convert Screenshot to byte
                Bitmap newBM = new Bitmap(bm, new Size(bm.Width / 2, bm.Height / 2));
                MemoryStream ms = new MemoryStream();
                bm.Save(ms, ImageFormat.Jpeg);
                //Write Screenshot into stream
                b1 = ms.ToArray();
                streamScreen.Write(b1, 0, b1.Length);
            
                Thread.Sleep(500);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }

私が試したこと:

これらの質問も参照しました。
1. C# TCP 読み取りすべてのデータ – サーバー側の問題[^]

2. https://stackoverflow.com/questions/52439851/c-sharp-tcp-how-can-i-get-exacly-amount-of-bytes-that-are-recived[^]

上記の解決策に記載されている方法を使用すると、ネットワークストリームがバイトを読み取ろうとするが、クライアントはまだデータをサーバーに送信し、サーバーはミリ秒ごとにデータを受信して​​いるため、無限ループに入ることがわかりました。

解決策 1

この CodeProject の記事を試してください。 Windows リモート デスクトップ アプリケーション[^]

おそらく、使用できる TCP ルーチンが含まれています。

解決策 2

RickZeeland のコメントに加えて、ネットワーク/ストリーミングに関して覚えておくべきもう 1 つの重要な点は、任意の時点で受信できるバイト数が保証されていないことです。

C#
byte[] bytes = new byte[1000000];
streamScreenShare.Read(bytes, 0, bytes.Length);

これは、「最大 1,000,00 バイトまで取得してください」と言っています。 ただし、何らかのネットワーク遅延や接続の問題があった場合、クライアントからすべてのバイトを受信できる保証はありません。 これは、100 バイトを含むバッファーを取得し、その後に 32,100 バイトを含む別のバッファーを取得する可能性があることを意味します。

アプリケーション内にパケット構造を作成することで、これを回避する人もいます。 たとえば、ストリームの最初の 4 バイトは、 Int32 次のイメージの長さ (バイト単位) です。 次に、画像バイトをストリーミングし、受信した数を数えて、全体像を確実に把握できるようにします。 画像のバイトを正常に処理した後、次の 4 バイトが次の画像の長さになることがわかります。



Source link

コメント

タイトルとURLをコピーしました