C#:如何在Compact Framework中设置AsyncWaitHandle?

时间:2010-03-16 16:18:32

标签: c# compact-framework asynchronous waithandle

我在我的一个Compact Framework 2.0应用程序中使用TcpClient。我想从TCP服务器接收一些信息。

由于Compact Framework不支持“大型”框架的超时机制,我正在尝试实现自己的超时功能。基本上,我想做以下事情:

IAsyncResult result = networkStream.BeginRead(buffer, 0, size, ..., networkStream);
if (!result.AsyncWaitHandle.WaitOne(5000, false))
  // Handle timeout


private void ReceiveFinished(IAsyncResult ar)
{
  NetworkStream stream = (NetworkStream)ar.AsyncState;
  int numBytes = stream.EndRead(ar);

  // SIGNAL IASYNCRESULT.ASYNCWAITHANDLE HERE ... HOW??
}

我想为Set调用IAsyncResult.AsyncWaitHandle,但它没有这样的方法,我不知道将它投射到哪个实现。

如何设置等待句柄?或者通过调用EndRead自动设置?文档表明我必须自己致电Set ......

感谢您的帮助!

更新
似乎在调用EndRead时自动设置了等待句柄 - 但它不在文档中。有人可以证实这一点吗?

更新2
在我的示例代码中写了client.BeginRead。当然,在BeginRead ...

上调用NetworkStream

1 个答案:

答案 0 :(得分:2)

我认为您对使用TCP的异步IO有误解。

要启动异步IO,请调用stream.BeginRead()。
在回调中,您在流上调用EndRead。

您不会在代码显示的TcpClient上调用BeginRead。您的应用程序不会发出WaitHandle信号。当等待句柄发出信号时,IO层将调用您的回调,换句话说,当异步读取发生时。

在你的回调中,通常你会在流上再次调用BeginRead,如果你可能会收到更多数据。

您可以在this answer中看到明确的示例。

在开始BeginRead / EndRead舞蹈之前, 您可能想在TcpClient上执行异步连接 - 然后您将使用BeginConnect。但这只做了一次。或者,您可能需要同步连接,在这种情况下,您只需调用TcpClient.Connect()。

示例代码:

    private class AsyncState
    {
        public NetworkStream ns;
        public ManualResetEvent e;
        public byte[] b;
    }

    public void Run()
    {
        NetworkStream networkStream = ...;
        byte[] buffer = new byte[1024];

        var completedEvent = new ManualResetEvent(false);

        networkStream.BeginRead(buffer, 0, buffer.Length,
                                AsyncRead,
                                new AsyncState
                                {
                                    b = buffer,
                                    ns = networkStream,
                                    e = completedEvent
                                });

        // do other stuff here. ...

        // finally, wait for the reading to complete
        completedEvent.WaitOne();
    }


    private void AsyncRead(IAsyncResult ar)
    {
        AsyncState state = ar as AsyncState;
        int n = state.ns.EndRead(ar);
        if (n == 0)
        {
            // signal completion
            state.e.Set();
            return;
        }

        // state.buffer now contains the bytes read
        // do something with it here...
        // for example, dump it into a filesystem file. 

        // read again
        state.ns.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
    }