了解NetworkStream.EndRead() - 来自MSDN的示例

时间:2013-10-01 09:46:15

标签: c# asynchronous tcpclient networkstream

我试图了解NetworkStream.EndRead()的MSDN示例。有些部分我不明白。

所以这是示例(从MSDN复制):

// Example of EndRead, DataAvailable and BeginRead.

public static void myReadCallBack(IAsyncResult ar ){

    NetworkStream myNetworkStream = (NetworkStream)ar.AsyncState;
    byte[] myReadBuffer = new byte[1024];
    String myCompleteMessage = "";
    int numberOfBytesRead;

    numberOfBytesRead = myNetworkStream.EndRead(ar);
    myCompleteMessage = 
        String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));    

    // message received may be larger than buffer size so loop through until you have it all.
    while(myNetworkStream.DataAvailable){

        myNetworkStream.BeginRead(myReadBuffer, 0, myReadBuffer.Length, 
                                               new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack), 
                                                   myNetworkStream);  

    }

    // Print out the received message to the console.
    Console.WriteLine("You received the following message : " +
                                myCompleteMessage);
}

它使用BeginRead()和EndRead()从网络流异步读取。 通过调用

来调用整个事情
myNetworkStream.BeginRead(someBuffer, 0, someBuffer.Length, new AsyncCallback(NetworkStream_ASync_Send_Receive.myReadCallBack), myNetworkStream);  

其他地方(示例中未显示)。

我认为它应该做的是在一个WriteLine(示例末尾的那个)中打印从NetworkStream接收的整个消息。请注意,该字符串名为myCompleteMessage

现在,当我查看实施时,我的理解会产生一些问题。

首先:该示例分配一个新的方法 - 本地缓冲区myReadBuffer。然后调用EndStream(),将收到的消息写入提供BeginRead()的缓冲区。这不是刚刚分配的myReadBuffer。网络流应该如何知道它?因此,在下一行numberOfBytesRead中,空缓冲区中的字节将附加到myCompleteMessage。其中包含当前值""。在最后一行中,此消息由大量'\0'组成,并使用Console.WriteLine打印。

这对我没有任何意义。

我不理解的第二件事是while - 循环。

BeginRead是异步调用。因此,不会立即读取任何数据。因此,据我所知,while循环应运行一段时间,直到实际执行某些异步调用并从流中读取,以便不再有可用的数据。文档没有说明BeginRead会立即将可用数据的某些部分标记为已读取,因此我不希望它这样做。

此示例不会提高我对这些方法的理解。这个例子是错的还是我的理解错了(我期待后者)?这个例子是如何工作的?

1 个答案:

答案 0 :(得分:7)

我认为BeginRead周围的 while循环不应该存在。在EndRead完成之前,您不希望执行的BeginRead多于BeginRead。此外,需要在BeginRead之外指定缓冲区,因为每个数据包/缓冲区可能使用多个读取。

您需要考虑一些事项,例如我的消息/块(固定大小)多长时间。我可以在前面添加一个长度。 (可变大小) <datalength><data><datalength><data>

不要忘记它是一个Streaming连接,因此可以在一次读取中读取多个/部分消息/数据包。

伪示例:

int bytesNeeded;
int bytesRead;

public void Start()
{
    bytesNeeded = 40; // u need to know how much bytes you're needing
    bytesRead = 0;

    BeginReading();
}

public void BeginReading()
{
    myNetworkStream.BeginRead(
        someBuffer, bytesRead, bytesNeeded - bytesRead, 
        new AsyncCallback(EndReading), 
        myNetworkStream);
}

public void EndReading(IAsyncResult ar)
{
    numberOfBytesRead = myNetworkStream.EndRead(ar);

    if(numberOfBytesRead == 0)
    {
        // disconnected
        return;
    }

    bytesRead += numberOfBytesRead;

    if(bytesRead == bytesNeeded)
    {
        // Handle buffer
        Start();
    }
    else
        BeginReading();
}