2

如果来自服务器的数据不多,或者如果有很多数据并且我取消注释该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(); }
    }
4

1 回答 1

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();
    }
}

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

于 2013-04-03T06:12:00.177 回答