5

TCP で複数のサーバーに接続する C# の WinRT でクライアント アプリをプログラミングしています。TCP 接続には StreamSocket を使用します。次に、入力文字列と出力文字列が DataWriter と DataReader にラップされます。複数のサーバーに接続すると、「操作識別子が無効です」という例外が発生します。

メソッドのコードは次のとおりです。

private async void read()
    {
        while (true)
        {
            uint bytesRead = 0;
            try
            {
                bytesRead = await reader.LoadAsync(receiveBufferSize);

                if (bytesRead == 0)
                {
                    OnClientDisconnected(this);
                    return;
                }
                byte[] data = new byte[bytesRead];
                reader.ReadBytes(data);
                if (reader.UnconsumedBufferLength > 0)
                {
                    throw new Exception();
                }

                OnDataRead(this, data);
            }
            catch (Exception ex)
            {
                if (Error != null)
                    Error(this, ex);
            }

            new System.Threading.ManualResetEvent(false).WaitOne(10);

        }
    }

Stacktrace は、問題の原因として reader.LoadAsync(UInt32 count) メソッドのみを示しています。各 ClientInstance は独自のタスクで実行され、独自の DataReader および Stream インスタンスを持ちます。「receiveBufferSize」は 8192 バイトです。

エラーが何であるか分かりますか?

4

2 に答える 2

8

私は今、私の質問に自分で答えることができると思います。問題は、LoadAsync メソッドが await/async コンストラクトと一緒にうまく機能しないことでした。メソッドは ThreadPool スレッド A によって呼び出され、ThreadPool スレッド B によって (待機後に) 再開されました。このコンスタレーションは例外をスローしました。しかし、その理由は一概には言えません...

この回答 ( WinRT 非同期タスクを既存の同期ライブラリに統合する方法は? ) で、LoadAsync メソッドを同期メソッドに記述しましたが、同じスレッドがメソッドを呼び出してその結果を使用するため、機能するようになりました。

変更されたコード フラグメントは次のとおりです。

IAsyncOperation<uint> taskLoad = reader.LoadAsync(receiveBufferSize);
taskload.AsTask().Wait();
bytesRead = taskLoad.GetResults();

スレッドで私を正しい道に導いてくれたGeoffに感謝します:)私もこの問題を抱えている人を助けることができれば幸いです。

于 2013-04-20T09:11:21.097 に答える
1

例外の可能性のある原因は、ドキュメントの次の部分であると思われます。

LoadAsync への以前の呼び出しがまだ完了していない場合。

さらに下を読む:

LoadAsync メソッドは、UI スレッドで 1 回だけ呼び出すことができます。LoadCompleted イベントが発生するまで、このメソッドを再度呼び出すことはできません。LoadCompleted イベントは、クエリが成功したかどうかにかかわらず発生します。

次に、それをasync/await が純粋な魔法のソースではない理由に関するこの非常に完全な回答と組み合わせます。

[...]await は、魔法のように同期メソッドを非同期で実行させるわけではありません。たとえば、新しいスレッドを開始して、新しいスレッドでメソッドを実行することはありません。

LoadAsync()そのため、最初の呼び出しが完了する前にの 2 番目の呼び出しが発生しているように見えます。どちらも同じ UI スレッドから作成されます。

于 2013-04-19T18:08:46.677 に答える