异步TcpClient没有及时读取所有数据
本文关键字:读取 数据 TcpClient 异步 | 更新日期: 2023-09-27 18:07:05
如果没有很多来自服务器的数据,或者如果有很多数据并且我取消注释Thread.Sleep(500)
行,下面的代码可以工作。然而,我不想使用Thread.Sleep
行,但是如果我删除它,程序将在从服务器读取所有数据之前完成。似乎问题是,EndRead()
不是阻塞,直到所有的数据被读取,这是可以理解的,应该与ReceiveCallback
的递归调用固定,但它不是。
我有一个在Linux上使用C/c++编写的工作客户端。我正试图使它与c#和。net一起工作。我在Linux上使用。net 4.0的MonoDevelop。我很感谢任何关于如何解决这个问题的帮助。
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(); }
}
问题是应用程序无法确定是否有更多的数据通过网络传入。它只知道它是否收到了任何数据。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();
}
}
回调函数将在接收到数据或连接终止时调用。一旦连接关闭,响应就完成了。