C#NetworkStream.Read()会等到读取指定数量的数据吗?

时间:2016-08-21 10:36:38

标签: c# networking

在C / C ++中,常规非阻塞网络套接字上的read()将立即返回缓冲区中当前可用的数据量,最多为指定的数量(因此,如果我们要求16个字节,则只有8个可用目前,我们已经获得了8个,我们可以再次调用read()并获取所有数据。

在C#中,NetworkStream具有内置超时功能 - 这意味着NetworkStream.Read()会等待,直到达到超时或读取请求的数据量为止,或者它会给我们缓冲区中当前可用的任何数据量大于0,直到请求的数量(如标准套接字那样),即使还剩下时间?

3 个答案:

答案 0 :(得分:1)

它将读取参数中指定的字节数的可用数据,如MSDN所述,除非通过超时或其他异常关闭流。

  

Read操作读取尽可能多的数据,最多可达size参数指定的字节数。如果远程主机关闭连接,并且已收到所有可用数据,则Read方法立即完成并返回零字节。

答案 1 :(得分:1)

我解决了这个问题:

        byte[] TotalData = new byte[0];
        byte[] TempData = new byte[0];
        using (TcpClient TCPClient = new TcpClient())
        {
            try
            {
                TCPClient.Connect(somehost, someport);
            }
            catch (Exception eee)
            {
                // Report the connection failed in some way if necessary
            }
            if (TCPClient.Connected)
            {
                using (NetworkStream clientStream = TCPClient.GetStream())
                {
                    // You can reduce the size of the array if you know 
                    // the data received is going to be small, 
                    // don't forget to change it a little down too

                    byte[] TCPBuffer = new byte[524288];
                    int bytesRead = 0;

                    int loop = 0;
                    // Wait for data to begin coming in for up to 20 secs
                    while (!clientStream.DataAvailable && loop< 2000)
                    {
                        loop++;
                        Thread.Sleep(10);
                    }
                    // Keep reading until nothing comes for over 1 sec
                    while (clientStream.DataAvailable)
                    {
                        bytesRead = 0;

                        try
                        {
                            bytesRead = clientStream.Read(TCPBuffer, 0, 524288);
                            Array.Resize(ref TempData, bytesRead);
                            Array.Copy(TCPBuffer, TempData, bytesRead);
                            // Add data to TotalData
                            TotalData = JoinArrays(TotalData, TempData);
                        }
                        catch
                        {
                            break;
                        }

                        if (bytesRead == 0)
                            break;

                        Thread.Sleep(1000);
                    }
                }
            }
        }

JoinArrays()方法:

byte[] JoinArrays(byte[] arrayA, byte[] arrayB)
{
    byte[] outputBytes = new byte[arrayA.Length + arrayB.Length];
    Buffer.BlockCopy(arrayA, 0, outputBytes, 0, arrayA.Length);
    Buffer.BlockCopy(arrayB, 0, outputBytes, arrayA.Length, arrayB.Length);
    return outputBytes;
}

答案 2 :(得分:0)

安全的方法是使用MemoryStream,这将确保等待并将所有流读取到内存中,然后您就可以随意使用它了

     public void SaveUserTemplate(Stream stream)
     {
        MemoryStream memoryStream = new MemoryStream();
        stream.CopyTo(memoryStream);
        memoryStream.Position = 0;

      
        byte[] templatePathLength = new byte[4];
        memoryStream.Read(templatePathLength, 0, templatePathLength.Length);
        int nBytesTemplatePathLength = BitConverter.ToInt32(templatePathLength,0);

        ....

CopyTo函数最终调用此函数:

github.com/microsoft/referencesource

private void InternalCopyTo(Stream destination, int bufferSize)
    {
        Contract.Requires(destination != null);
        Contract.Requires(CanRead);
        Contract.Requires(destination.CanWrite);
        Contract.Requires(bufferSize > 0);
        
        byte[] buffer = new byte[bufferSize];
        int read;
        while ((read = Read(buffer, 0, buffer.Length)) != 0)
            destination.Write(buffer, 0, read);
    }