C#,异步任务和NetworkStream.BeginRead,如何保证缓冲区获胜';不会被覆盖

本文关键字:覆盖 获胜 何保证 任务 异步 NetworkStream BeginRead 缓冲区 | 更新日期: 2023-09-27 17:59:39

我正试图用C#编写一段代码,以异步方式从TcpClient读取。这是我的代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
class Connection
{
    private TcpClient socket;
    private NetworkStream socketStream;
    private byte[] buffer;
    private int bytesRead;
    private Task<int> readTask;
    public Connection(TcpClient socket)
    {
        this.socket = socket;
        socketStream = socket.GetStream();
        buffer = new byte[4096];
        readTask = Task.Factory.FromAsync<byte[], int, int, int>(
            this.socketStream.BeginRead
            , this.socketStream.EndRead
            , this.buffer
            , 0
            , this.buffer.Length
            , null
        );
        readTask.ContinueWith(
            (task) => {
                this.bytesRead = (int)task.Result;
                //Do something with buffer.
            }
            , TaskContinuationOptions.OnlyOnRanToCompletion
        );
    }
}

问题是异步BeginRead将尝试在Connection对象的缓冲区上进行写入,一旦新数据到达,无论是否消耗,旧数据都将被覆盖。我应该如何解决这个问题?AFAIK这应该与关闭有关,但我不知道怎么回事!

C#,异步任务和NetworkStream.BeginRead,如何保证缓冲区获胜';不会被覆盖

您必须有一个需要处理的缓冲区集合。您可以简单地分配一个本地缓冲区(var buffer = new byte[4096];),然后将该缓冲区添加到延续中的集合(可能是Stack)中。您可能还需要通知另一个线程来处理队列中的新数据。

例如:

class Connection
{
    private TcpClient socket;
    private NetworkStream socketStream;
    private int bytesRead;
    private Task<int> readTask;
    private Stack<byte[]> buffersToProcess;
    private readonly object lockObject = new object();
    public Connection(TcpClient socket)
    {
        this.socket = socket;
        socketStream = socket.GetStream();
        var buffer = new byte[4096];
        readTask = Task.Factory.FromAsync<byte[], int, int, int>(
            this.socketStream.BeginRead
            , this.socketStream.EndRead
            , buffer
            , 0
            , buffer.Length
            , null
            );
        readTask.ContinueWith(
            (task) =>
                {
                    this.bytesRead = (int) task.Result;
                    var actualBytes = new byte[bytesRead];
                    Array.Copy(buffer, 0, actualBytes, 0, bytesRead);
                    lock (lockObject)
                    {
                        buffersToProcess.Push(actualBytes);
                    }
                    // TODO: do something with buffersToProcess
                }
            , TaskContinuationOptions.OnlyOnRanToCompletion
            );
    }
}

但是,你真的没有提供足够的信息来真正说明你在这种情况下真正需要什么。例如,为什么之前的缓冲区还没有处理?