我有一个listen()函数正在读取网络流和一个回调函数newDataRecievedCallback。
我调用 BeginRead 方法 Async ,但我再次在回调函数中调用相同的方法。那不是同步逻辑吗?
还有其他方法吗?
private void listen()
{
networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
}
private void newDataRecievedCallback(IAsyncResult rst)
{
try
{
int recievedDataSize = tcpClient.Client.Receive(buffer);
recievedData = convertToString(buffer, incomeDataSize);
//End Read
networkStream.EndRead(rst);
cleanBuffer();
parseXMLData(recievedData);
//Hier I call the same async method
networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(newDataRecievedCallback), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
答案 0 :(得分:4)
如果 BeginRead
总是异步完成,那么在回调中再次调用它仍然是异步的。
但是BeginRead
有时会同步完成(检查IAsyncResult.CompletedSynchronously
),因此当你运气不好时,你的代码容易受到堆栈溢出的影响。例如,这可能发生在一个线程中:newDataRecievedCallback
- > BeginRead
- > newDataRecievedCallback
- > BeginRead
等等。
使用BeginRead
的正确方法是使用类似于下面的模式(这是一个来自C#4.0的Nutshell中的code snippet)。实质上,您应该始终检查方法是否同步完成,然后采取适当的行动。
void Read() // Read in a nonblocking fashion.
{
while (true)
{
IAsyncResult r = _stream.BeginRead
(_data, _bytesRead, _data.Length - _bytesRead, ReadCallback, null);
// This will nearly always return in the next line:
if (!r.CompletedSynchronously) return; // Handled by callback
if (!EndRead (r)) break;
}
Write();
}
void ReadCallback (IAsyncResult r)
{
try
{
if (r.CompletedSynchronously) return;
if (EndRead (r))
{
Read(); // More data to read!
return;
}
Write();
}
catch (Exception ex) { ProcessException (ex); }
}
bool EndRead (IAsyncResult r) // Returns false if there’s no more data
{
int chunkSize = _stream.EndRead (r);
_bytesRead += chunkSize;
return chunkSize > 0 && _bytesRead < _data.Length; // More to read
}
答案 1 :(得分:3)
它仍然是异步的,因为您对networkStream.BeginRead
的调用不会阻止。您拨打电话然后退出该功能。是的,它会被再次调用,但仍然是异步的。
还有其他方法吗?是的,有数百种方式。你的代码还不错。它似乎有点紧密耦合,因为您的异步处理程序正在执行自己的管理以及处理数据。更简洁的方法是使用newDataRecievedCallback
通过委托通知的某种控制器,并将数据传递给它进行处理。控制器还将负责产生下一个异步过程。单独的控制器也可以传递接收的数据进行处理,而不会阻止更多的异步调用。