简体   繁体   English

Determinig end of stream in.Net for Network Stream Reading

[英]Determinig end of stream in .Net for Network Stream Reading

I start learning to work with socket recently.我最近开始学习使用套接字。 The behaviour I see in documentation is that when reading stream with a buffer, it return zero to indicate reader reached end of stream.我在文档中看到的行为是,当使用缓冲区读取 stream 时,它返回零以指示读取器已到达 stream 的末尾。

private static async Task ProcessStreamAsync(NetworkStream stream)
        {
            while (true)
            {   
                var buffer = new Byte[64];
                var received = await stream.ReadAsync(buffer);
                Console.WriteLine($"Count:{received}");    
                var message = Encoding.UTF8.GetString(buffer, 0, received);
                Console.WriteLine(message);
                if (received == 0) break; // This line does not reach ever in my case!                  
            }

        }

But it is not the case I see in my code.但我在我的代码中看到的情况并非如此。 In the last reading loop, it returns a buffer which is not full and then wait infinitely.在最后一个读取循环中,它返回一个未满的缓冲区,然后无限等待。 I try to handle it with comparing buffer length and buffer capacity.我尝试通过比较缓冲区长度和缓冲区容量来处理它。

private static async Task ProcessStreamAsync(NetworkStream stream)
        {
            while (true)
            {
                var buffer = new Byte[64];
                var received = await stream.ReadAsync(buffer);
                Console.WriteLine($"Count:{received}");
                var message = Encoding.UTF8.GetString(buffer, 0, received);
                Console.WriteLine(message);
                // if (received == 0) break;
                if (received < buffer.Length) { break; }

            }

        }

but this is not possible in case of using PipeReader which allocates buffer automatically and buffer size is not available in APIs.但是如果使用自动分配缓冲区的 PipeReader 并且缓冲区大小在 API 中不可用,则这是不可能的。

private static async Task ProcessWithPipes(NetworkStream stream)
        {
            var reader = PipeReader.Create(stream);
            var writer = PipeWriter.Create(stream);    

            try
            {
                bool completed = false;
                do
                {
                    var result = await reader.ReadAsync();    
                    if (result.Buffer.Length == 0)
                    {
                        completed = true;
                        Console.WriteLine("Receive Empty Buffer, Client Closed");
                    }
                    var buffer = result.Buffer;
                    if (buffer.IsSingleSegment)
                    {
                        string message = Encoding.UTF8.GetString(buffer);
                        Console.WriteLine(message);
                    }
                    else
                    {
                        foreach (var item in buffer)
                        {
                            string message = Encoding.UTF8.GetString(item.Span);
                            Console.WriteLine(message);
                        }

                    }
                    if (result.IsCompleted)
                    {
                        completed = true;
                        Console.WriteLine("Stream Reading Completed, Client Closed");
                    }
                    var nextPosition = buffer.GetPosition(buffer.Length);
                    reader.AdvanceTo(nextPosition);

                } while (!completed);
                await reader.CompleteAsync();


            }
            catch (System.Exception)
            {

                throw;
            }
        }
    }

By the way I am using linux ubuntu for my development.顺便说一句,我正在使用 linux ubuntu 进行开发。 Is this a normal behaviour?这是正常行为吗?

I think changing the method you use will also solve your problem.我认为改变你使用的方法也会解决你的问题。 You can get healthier results by using the method I shared the link of.您可以使用我分享链接的方法获得更健康的结果。 I will be glad if you inform me about the result.如果你能告诉我结果,我会很高兴。

Try This;试试这个; https://stackoverflow.com/a/26059057/12645793 https://stackoverflow.com/a/26059057/12645793

After reading responses and comments, I found two way for solving this: 1- Use underlying.network stream DataAvailable property instead of ReadResult IsCompleted or Buffer.Length==0 to break the while loop as below:阅读回复和评论后,我找到了解决此问题的两种方法:1- 使用 underlying.network stream DataAvailable属性而不是 ReadResult IsCompletedBuffer.Length==0来打破 while 循环,如下所示:

private static async Task ProcessWithPipes(NetworkStream stream)
        {
            var reader = PipeReader.Create(stream); 

            try
            {
                bool completed = false;
                do
                {
                    var result = await reader.ReadAsync();    
                    if (!stream.DataAvailable)
                    {
                        completed = true;
                        Console.WriteLine("Receive Empty Buffer, Client Closed");
                    }
                    var buffer = result.Buffer;
                    if (buffer.IsSingleSegment)
                    {
                        string message = Encoding.UTF8.GetString(buffer);
                        Console.WriteLine(message);
                    }
                    else
                    {
                        foreach (var item in buffer)
                        {
                            string message = Encoding.UTF8.GetString(item.Span);
                            Console.WriteLine(message);
                        }

                    }
                    if (result.IsCompleted)
                    {
                        completed = true;
                        Console.WriteLine("Stream Reading Completed, Client Closed");
                    }
                    var nextPosition = buffer.GetPosition(buffer.Length);
                    reader.AdvanceTo(nextPosition);

                } while (!completed);
                await reader.CompleteAsync();


            }
            catch (System.Exception)
            {

                throw;
            }
        }
    }

2- Use PipeWriter to fill pipe with.network stream and then use PipeReader to read it 2-用PipeWriter把pipe填成.network stream然后用PipeReader读取

private static async Task ProcessStreamUsingPipe(Socket socket)
        {
            Pipe pipe = new Pipe();
            Task writing = FillPipeAsync(socket, pipe.Writer);
            Task reading = ReadPipeAsync(pipe.Reader);
            await Task.WhenAll(writing, reading);
        }
        private static async Task FillPipeAsync(Socket client, PipeWriter writer)
        {
            const int minimumBuffersize = 32;
            while (true)
            {
                var buffer = writer.GetMemory(minimumBuffersize);
                try
                {
                    int received = await client.ReceiveAsync(buffer, SocketFlags.None);
                    Console.WriteLine($"Received Count:{received}");
                    var result = await writer.FlushAsync();.
                    writer.Advance(received); 
                    if (received < buffer.Length) break;
                    if (result.IsCompleted)
                    {
                        break;
                    }

                }
                catch (System.Exception)
                {
                    throw;
                }
            }
            await writer.CompleteAsync(); 
        }
        private static async Task ReadPipeAsync(PipeReader reader)
        {

            while (true)
            {
                var result = await reader.ReadAsync();
                var buffer = result.Buffer;
                var msg = Encoding.UTF8.GetString(buffer);
                Console.WriteLine(msg);
                reader.AdvanceTo(buffer.Start);
                if (result.IsCompleted) break;
            }

            await reader.CompleteAsync();
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM