0

我正在尝试用 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 它应该与闭包有关,但我不知道怎么做!

4

1 回答 1

2

您必须拥有一组需要处理的缓冲区。您可以简单地分配一个本地缓冲区(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
            );
    }
}

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

于 2013-02-15T17:49:35.333 回答