8

全般的

ポート番号を使用してIPアドレスに接続し、非常に単純なラインコマンドを要求してから、応答をGridbox、グラフ、またはその他の表示オプションに配置するために、C#で非常に単純なTCPIPクライアントサーバーを作成しようとしています。

私がオンラインで調べたところ、Jayan Nair によって書かれた、まさにこれを行うダウンロード可能なユーティリティが見つかりました。これは、メッセージを正しく送信し、応答を正常に受信しているようです。

問題は、返信データをリッチテキストまたは GridView に読み込もうとしたときに発生します。

私が得ているエラーメッセージは次のとおりです:- System.InvalidOperationException

Microsoft フォーラムに問い合わせたところ、何をすべきかについて、非常に複雑で、あいまいで、過度に複雑な指示がありました。これには、INVOKE と BeginInvoke と呼ばれるものが含まれており、すべてが独自のプロジェクトのようです。右。

私が求めているのは、複雑になりすぎずに機能する単なる例です。

コードは次のとおりです:-

        try
        {
            SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
            int iRx = theSockId.thisSocket.EndReceive(asyn);
            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
            // 
            System.String szData = new System.String(chars);
            richTextRxMessage.Text =  szData;  // fails
            //textBox1.Text = szData;          // also fails
            WaitForData();
        }

エラーメッセージは次のとおりです:-

base {System.Windows.Forms.TextBoxBase} = {Text = '((System.Windows.Forms.RichTextBox)    (((System.Windows.Forms.RichTextBox)(richTextRxMessage)))).Text' threw an exception of type   'System.InvalidOperationException'}

追加情報は次のとおりです: -szDataには、タブ(9)とリターン(13)を含む約6300文字が含まれており、サーバーから送信されたメッセージと一致していますリッチテキストの代わりにテキストボックスを使用して試しましたが、同じ結果です

興味のある方へ

マイクロソフトのリンクはこちら

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/12a67fb0-847e-4e2b-baa8-ef6ceed60aa4/


  • これは、私が試したコード修正のうちの2つだけです。両方とも同じエラー状態で失敗します
  • 私がする必要があるのは、C# をはるかに低いレベルから開始することであり、飛び込んで最善を尽くすだけではありません。


       public void OnDataReceived(IAsyncResult asyn)
        {
    
            int InputRx;
            int charLen;
            char[] Inputchars;
            System.Text.Decoder InputDecode;
            System.String szData;
            bool IfInvokeRequired;
    
            try
    
            {
    
                SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
                InputRx = theSockId.thisSocket.EndReceive(asyn);                    // get size of input array
                Inputchars = new char[InputRx + 1];                                   // put i char array
                InputDecode = System.Text.Encoding.UTF8.GetDecoder();
                charLen = InputDecode.GetChars(theSockId.dataBuffer, 0, InputRx, Inputchars, 0);
                szData = new System.String(Inputchars);
                IfInvokeRequired = richTextRxMessage.InvokeRequired;
                if (IfInvokeRequired == true)
                {
                    richTextRxMessage.Invoke((MethodInvoker)delegate { this.Text = szData; });// fails
                    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));//fails as well
                }
    
  • 4

    4 に答える 4

    5

    受信したInvalidOperationExceptionには、内部例外「別のスレッドが所有しているため、呼び出し元のスレッドはこのオブジェクトにアクセスできません」が含まれている可能性があります。

    デバッグのために、すぐCheckForIllegalCrossThreadCallsに false に設定できます。これにより、ランタイムが例外をスローするのを防ぎますが、例外を受け取っていないからといって、例外が発生していないわけではないため、これは分散ソフトウェアでは悪い習慣ですが、デバッグには非常に便利です。

    問題を解決するRichTextBoxには、UI スレッド(コントロールが作成されたスレッド) とやり取りするコードと、コントロールとやり取りするコードを実行できる唯一のスレッドを呼び出す必要があります。

    UI スレッドでコードを呼び出すには、次の簡潔なステートメントを使用できます。

    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));
    

    非常に簡単に言えば、ここで行っていることは、デリゲートを使用して UI スレッドで呼び出したいステートメントを渡すことだけです。

    于 2013-03-14T13:48:23.710 に答える
    1

    これは、私が自分のもののいくつかで使用する関数です。

    public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
    {
        if (@this.InvokeRequired)
        {
            @this.Invoke(action, new object[] { @this });
        }
        else
        {
            action(@this);
        }
    }
    

    これは、あらゆる種類の呼び出しを処理するための非常に優れた小さなメソッドであり、使用するとコード行が削減されます。使用するには、これを使用するだけです。

    Control.InvokeEx(f => control.DoStuff());
    

    たとえば、次のように使用できます。

    richTextRxMessage.InvokeEx(f => richTextRxMessage.Text =  szData);
    

    編集:他の人が言ったように、このエラーは、作成されたスレッド以外のスレッドでコントロールにアクセスすることが原因である可能性が高いため、呼び出しが必要です。

    于 2013-03-14T13:49:48.367 に答える
    0

    マイクロソフトの回答は完全に間違っているわけではありませんが、見た目はわかりませんが、もう少し簡単な方法が他にもあります。

    これは、役に立つかもしれない私自身のコードの抜粋です。

    if (dirtyImage.InvokeRequired)
    {
        dirtyImage.Invoke(new MethodInvoker(delegate { Visible = RigX.IsDirty; }));
        dirtyImage.Invoke(new MethodInvoker(delegate { Refresh(); }));
    }
    else
    {
        dirtyImage.Visible = RigX.IsDirty;
        dirtyImage.Refresh();
    }
    

    InvokeRequiredと の使用方法に注意してくださいdirtyImage.Invoke(...)。デリゲートを作成し、メソッド インボーカーを使用することで、すべての呼び出しを 1 つのライナーにすることで、はるかに簡単にします。デリゲートは基本的にミニメソッドを作成し、それが MethodInvoker を使用して呼び出されます。ただし、変更は UI スレッド上にあるため、 を使用せずにバックグラウンド スレッドから呼び出すことはできません.Invoke。これは許可されていません。

    この方法で呼び出しを変更する方法は次のとおりです。

    richTextRxMessage.Invoke(new MethodInvoker(delegate { Text =  szData; }));
    

    その呼び出しはUIスレッド自体からも直接機能するため、実際にはifステートメントは必要ありませんが、「コスト」に関しては、プロパティを直接呼び出すよりも遅くなります。

    もちろん、これは、最初からバックグラウンド スレッドを使用している場合にのみ、実際に違いが生じます。そうでない場合は、エラー自体を調査する必要があります。返品のテキストに問題がある可能性があります。それをファイルに書き込んで見て、問題を見つけられるかどうかを確認してください。RTB のテキストを手動で設定してみて、それが可能かどうかを確認してください。などなど。

    于 2013-03-14T13:41:56.360 に答える
    0

    この問題は、MS フォーラムで提案されているマルチスレッドが原因である可能性があります。この操作を非同期で要求すると、入力を処理する別のスレッドが作成され、メイン アプリケーション スレッドがブロックされなくなります。

    この問題を解決するにはInvoke、プロパティを変更するコントロールが必要です。メイン アプリケーション スレッドが UI を所有し、UI に対する操作は別のスレッドから実行できないため、これが必要です。

    呼び出しは複雑ではなく、数行で実行できます。

    次の行を変更します

    richTextRxMessage.Text =  szData;
    

    richTextRxMessage.Invoke((MethodInvoker) delegate {this.Text = szData;});
    

    richTextRxMessageこのコードは、テキスト自体を更新するのではなく、メインの UI スレッドにテキストを更新するように要求します。

    于 2013-03-14T13:48:34.437 に答える