1

我在我的TcpClient一个 Compact Framework 2.0 应用程序中使用了一个。我想从 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??
}

我想调用SetIAsyncResult.AsyncWaitHandle但它没有这样的方法,我不知道将它转换为哪个实现。

如何设置等待句柄?还是通过调用自动设置EndRead?文档表明我必须称Set自己为...

谢谢你的帮助!

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

更新 2
client.BeginRead在我的示例代码中。当然,BeginRead被称为NetworkStream...

4

1 回答 1

2

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

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

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

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

您可以在此答案中看到一个清晰的示例。

在开始 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);
    }
于 2010-03-18T02:48:05.607 回答