异步TcpClient没有及时读取所有数据

时间:2013-04-03 05:58:29

标签: c# .net asynchronous tcpclient beginread

如果没有来自服务器的大量数据,或者如果有大量数据并且我取消注释Thread.Sleep(500)行,则下面的代码有效。但是我不想使用Thread.Sleep行,但如果删除它,程序将在从服务器读取所有数据之前完成。似乎问题是EndRead()在读取所有数据之前没有阻塞,这是可以理解的,应该通过递归调用ReceiveCallback来修复,但事实并非如此。

我在Linux上使用C / C ++编写了一个工作客户端。我正在尝试使用c#和.Net。我在Linux上使用MonoDevelop和.Net 4.0。我很感激如何解决这个问题。

cli.send("command");
// Thread.Sleep(500); 
cli.receive();
Console.WriteLine("response: {0}", cli.Response);
    private Static ManualResetEvent recvEvt = new ManualResetEvent(false);

    public static void receive() {
        StateObject state = new StateObject();
        try {
            state.stream = client.GetStream();
            state.stream.BeginRead(state.buffer, 0, state.bufferSize, new AsyncCallback(ReceiveCallback), state);
            recvEvt.WaitOne();
            recvEvt.Reset();
        }
        catch (ArgumentNullException ne) { errorMessage = ne.ToString(); }
        catch (ArgumentException ae) { errorMessage = ae.ToString(); }
        catch (ObjectDisposedException oe) { errorMessage = oe.ToString(); }
        catch (InvalidOperationException ie) { errorMessage = ie.ToString(); }
        catch (SocketException se) { errorMessage = se.ToString(); }
    }


   private static void ReceiveCallback(IAsyncResult ar) {
        StateObject state = (StateObject)ar.AsyncState;
        try {
            int bytesRead = state.stream.EndRead(ar);
            if (bytesRead > 0 ) {
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                response = state.sb.ToString();
                if (state.stream.DataAvailable) {
                    state.stream.BeginRead(state.buffer, 0, state.bufferSize, new AsyncCallback(ReceiveCallback), state);
                    recvEvt.WaitOne();
                    recvEvt.Reset();
                }else
                    recvEvt.Set();
            }else
                recvEvt.Set();
        }
        catch (ArgumentNullException ne) { errorMessage = ne.ToString(); }
        catch (ArgumentException ae) { errorMessage = ae.ToString(); }
        catch (ObjectDisposedException oe) { errorMessage = oe.ToString(); }
        catch (InvalidOperationException ie) { errorMessage = ie.ToString(); }
        catch (SocketException se) { errorMessage = se.ToString(); }
    }

1 个答案:

答案 0 :(得分:3)

问题在于,应用程序无法确定是否有更多数据通过网络传入。它只知道它是否收到了任何数据。 DataAvailable将告诉您的是,是否有可以从网络流中读取的数据。远程端尚未发送给您的数据以及它已发送但尚未通过网络传送给您的数据对您的应用程序来说基本上是未知的。

您必须重复再次呼叫BeginRead,直到您或远程端挂断为止。有点简化的ReceiveCallback看起来像这样:

private static void ReceiveCallback(IAsyncResult ar) {
    StateObject state = (StateObject)ar.AsyncState;
    int bytesRead = state.stream.EndRead(ar);
    if (bytesRead > 0 ) {
        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
        state.stream.BeginRead(state.buffer, 0, state.bufferSize, new AsyncCallback(ReceiveCallback), state);
    } else {
        response = state.sb.ToString();
    }
}

一旦收到数据或终止连接,将调用回调。一旦连接关闭,响应就完成了。

相关问题