使用StreamSocket TCP的WinRT:DataReader.LoadAsync异常

时间:2013-04-19 17:45:39

标签: c# winrt-async

我正在使用C#在WinRT上编写客户端应用程序,该应用程序通过TCP连接到多个服务器。对于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计数)方法作为问题的根源。 每个ClientInstance都在自己的任务中运行,并拥有自己的DataReader和Stream实例。 “receiveBufferSize”为8192字节。

你知道错误是什么吗?

2 个答案:

答案 0 :(得分:8)

我想我现在可以自己回答我的问题了。问题是LoadAsync方法与await / async构造不能很好地协同工作。该方法由ThreadPool线程A调用,然后由ThreadPool线程B恢复(等待之后)。这个星座引发了异常。但我不能确切地说为什么......

通过这个答案(How to integrate WinRT asynchronous tasks into existing synchronous libraries?),我将LoadAsync方法写入同步方法,现在它可以正常工作,因为同一个线程正在调用该方法并使用它的结果。

以下是修改后的代码片段:

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

感谢Geoff带着我走向正确的道路:) 我希望我能帮助那些也会(将)解决这个问题的人。

答案 1 :(得分:1)

在我看来,异常的可能原因是这件from the documentation

  

以前对LoadAsync的调用尚未完成。

进一步阅读:

  

只能在UI线程上调用一次LoadAsync方法。该   在LoadCompleted事件发生之后才能再次调用方法   提高。无论查询是否,都会引发LoadCompleted事件   成功。

然后,将其与this very thorough answer结合起来,了解为什么async / await不仅仅是纯魔术酱:

  

[...] await不会神奇地导致同步方法运行   异步。它不会启动新线程并运行该方法   例如,在新线程上。

所以看来LoadAsync()的第二次调用是在第一次完成之前发生的;两者都是由相同的UI线程组成的。