从MSDN了解NetworkStream.EndRead()示例

9

我尝试理解MSDN关于NetworkStream.EndRead()的示例,但有一些部分我不太明白。

这是示例(来自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中。它的当前值为""。在最后一行,使用Console.WriteLine打印这条由许多'\0'组成的消息。

这对我来说毫无意义。

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

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

这个示例并没有提高我对这些方法的理解。这个示例是错误的还是我的理解是错误的(我期望后者)?这个示例如何工作?


4
这个例子完全错误,非常错误。 - Hans Passant
一个网络流应该像任何常规流一样工作,因此请参考以下 MSDN 示例:https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.readasync?view=netframework-4.7.2 - jdweng
这是一个更有帮助的MSDN示例:https://learn.microsoft.com/en-us/dotnet/framework/network-programming/using-an-asynchronous-client-socket - Jon R
1个回答

6
我认为在BeginRead周围的while循环不应该存在。在EndRead完成之前,您不希望执行多次BeginRead。此外,缓冲区需要在BeginRead之外指定,因为您可能会使用一个以上的读取每个数据包/缓冲区。
有一些需要考虑的事情,比如我的消息/块有多长(固定大小)。我应该在前面加上长度(变量大小)<datalength><data><datalength><data> 不要忘记这是一个流连接,因此可以在一个读取中读取多个/部分消息/数据包。
伪代码示例:
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();
}

是的,这样对我来说更有意义。 - jsf
你需要知道你需要多少字节吗?考虑到一个连续的流,所以你不需要知道你需要多少字节。你的伪代码示例并不是微软在他们的示例中所想要表述的内容 - 一个连续的流 - 想象一下电台的回放。然而,微软的示例也很糟糕。仍在寻找一个完整的实现... - Dan M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接