C# 试图使代码异步但不阻塞我的程序正在运行?

C# 试图使代码异步但不阻塞我的程序正在运行?,c#,asynchronous,C#,Asynchronous,编写客户机/服务器程序,以前使用的调用如下: TcpListener.AcceptTcpClient()NetworkStream.Read()NetworkStream.Write() TcpListener.AcceptTcpClient()工作正常,因为只有在建立连接后才调用其回调函数 但是,BeginRead()也不起作用。由于某些原因,即使没有发送数据,它也会执行并继续执行。。不知道发生了什么事NetworkStream.Read()阻塞得很好,但实际情况并非如此 以下是建立连接时创建

编写客户机/服务器程序,以前使用的调用如下:

TcpListener.AcceptTcpClient()
NetworkStream.Read()
NetworkStream.Write()

TcpListener.AcceptTcpClient()
工作正常,因为只有在建立连接后才调用其回调函数

但是,
BeginRead()
也不起作用。由于某些原因,即使没有发送数据,它也会执行并继续执行。。不知道发生了什么事
NetworkStream.Read()
阻塞得很好,但实际情况并非如此

以下是建立连接时创建的非工作线程:

private void HandleClientCommunication(object client)
{
    TcpClient tcpClient = (TcpClient)client;
    NetworkStream clientStream = tcpClient.GetStream();

    try
    {
        byte[] header = new byte[4];

        clientStream.BeginRead(header, 0, header.Length, Read, new StateData(clientStream, header)); // Runs even if no data is sent

        int dataLength = BitConverter.ToInt32(header, 0); // Continues to this, even if no packets are sent..

        byte[] data = new byte[dataLength]; // dataLength is 0 still of course because none of the code is blocking

        clientStream.BeginRead(data, 0, dataLength, Read, new StateData(clientStream, data));
    }
    catch (IOException e)
    {
        Console.WriteLine(e.InnerException.Message);
    }

    // not relevant past here
}
这里还有Read方法。不确定是否需要它来解决问题,但不管怎样,我将包括它:

private void Read(IAsyncResult async)
{
    StateData stateData = (StateData)async.AsyncState;

    stateData.BytesRead += stateData.Stream.EndRead(async);

    if (stateData.BytesRead < stateData.Bytes.Length)
    {
        stateData.Stream.BeginRead(stateData.Bytes, 0, stateData.Bytes.Length, Read, stateData);
    }
    else
    {
        string message = Encoding.ASCII.GetString(stateData.Bytes);

        Console.WriteLine(message);
    }
}
private void Read(IAsyncResult异步)
{
StateData StateData=(StateData)async.AsyncState;
stateData.BytesRead+=stateData.Stream.EndRead(异步);
if(stateData.BytesRead
所以,是的,我只是尝试建立一个客户端-服务器交互,使用异步调用,让每个“数据包”包含一个数据长度为int的报头,然后紧接着就是数据本身。不幸的是,事情似乎不起作用,我不确定问题出在哪里

似乎我必须包括一些手动形式的阻塞,但这不违背使用异步调用的目的吗?那么,为什么不回到常规的同步阻塞调用,比如此时的
Read()
AcceptTcpClient()

我想我对这里的事情还不是很了解

但是,beginhead()也不起作用。由于某些原因,即使没有发送数据,它也会执行并继续执行。。不知道发生了什么事。NetworkStream.Read()阻塞得很好,但这不是

我想你误解了我的意思。它不是用来阻塞的——它发出一个异步读取,在读取完成时执行给定的回调。它的意思是立即返回-所以难怪你的头数据是空的

基本上,任何需要数据的工作都应该在回调中,而不是使用调用
BeginRead
的方法。您的第一次回调应该转换标题数据,然后使用另一个回调再次转换
BeginRead
,以读取消息数据本身。。。尽管您还应该记住,任何
Read
/
BeginRead
调用都可能无法读取您请求的所有数据。您试图在回调中解释这一点,但您还没有完全做到,因为您总是试图从一开始就填充缓冲区,这将覆盖任何现有数据。如果您知道需要的数据总量以及缓冲区的长度,那么应该从已经读取的字节数开始读取缓冲区

请注意,C#5将使所有这一切变得更加简单-但是如果您不能等到那时,您可能会发现返回到阻止多线程(每个客户端一个)上的调用更容易

但是,beginhead()也不起作用。由于某些原因,即使没有发送数据,它也会执行并继续执行。。不知道发生了什么事。NetworkStream.Read()阻塞得很好,但这不是

我想你误解了我的意思。它不是用来阻塞的——它发出一个异步读取,在读取完成时执行给定的回调。它的意思是立即返回-所以难怪你的头数据是空的

基本上,任何需要数据的工作都应该在回调中,而不是使用调用
BeginRead
的方法。您的第一次回调应该转换标题数据,然后使用另一个回调再次转换
BeginRead
,以读取消息数据本身。。。尽管您还应该记住,任何
Read
/
BeginRead
调用都可能无法读取您请求的所有数据。您试图在回调中解释这一点,但您还没有完全做到,因为您总是试图从一开始就填充缓冲区,这将覆盖任何现有数据。如果您知道需要的数据总量以及缓冲区的长度,那么应该从已经读取的字节数开始读取缓冲区


请注意,C#5将使所有这一切变得更加简单-但如果您不能等到那时,您可能会发现返回到阻止多线程调用(每个客户端一个)更容易。

感谢您的回复。似乎回调正在执行,即使没有读取任何内容。当连接显然没有数据时,BeginRead的回调就会正确执行。不知道如何继续。@Gabriel:这可能是因为您正在发出第二个Beginhead调用,请求0字节的数据。它可能是立即执行的调用的回调。在第一次阅读结束之前,你真的不应该再调用
BeginRead
。你解释得很好。。我想我要买你的书。。lol@GabrielJohnson:如果你喜欢,我希望你喜欢——很抱歉这里没有更简单的答案;异步目前是一个难题。不过,请仔细阅读C#5,它会让事情变得更简单:)谢谢你的回复。似乎回调正在执行,即使没有读取任何内容。当连接显然没有数据时,BeginRead的回调就会正确执行。不知道如何继续。@Gabriel:这可能是因为您正在发出第二个Beginhead调用,请求0字节的数据。它可能是立即执行的调用的回调。