.NET 异步流读/写 [英] .NET Asynchronous stream read/write

查看:21
本文介绍了.NET 异步流读/写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试解决这个并发编程"考试练习(在 C# 中):

I have been trying to solve this "Concurrent Programming" exam exercise (in C#):

知道 Stream 类包含 int Read(byte[] buffer, int offset, int size)void Write(byte[] buffer, int offset), int size) 方法,在 C# 中实现了 NetToFile 方法,该方法将从 NetworkStream net 实例接收到的所有数据复制到 FileStream 文件实例.要进行传输,请使用异步读取和同步写入,避免在读取操作期间阻塞一个线程.当net读操作返回值0时,传输结束.为简化起见,不需要支持操作的受控取消.

Knowing that Stream class contains int Read(byte[] buffer, int offset, int size) and void Write(byte[] buffer, int offset, int size) methods, implement in C# the NetToFile method that copies all data received from NetworkStream net instance to the FileStream file instance. To do the transfer, use asynchronous reads and synchronous writes, avoiding one thread to be blocked during read operations. The transfer ends when the net read operation returns value 0. To simplify, it is not necessary to support controlled cancel of the operation.

void NetToFile(NetworkStream net, FileStream file);

我一直在尝试解决这个练习,但我正在为一个与问题本身相关的问题而苦苦挣扎.但首先,这是我的代码:

I've been trying to solve this exercise, but I'm struggling with a question related with the question itself. But first, here is my code:

public static void NetToFile(NetworkStream net, FileStream file) {
    byte[] buffer = new byte[4096]; // buffer with 4 kB dimension
    int offset = 0; // read/write offset
    int nBytesRead = 0; // number of bytes read on each cycle

    IAsyncResult ar;
    do {
        // read partial content of net (asynchronously)
        ar = net.BeginRead(buffer,offset,buffer.Length,null,null);
        // wait until read is completed
        ar.AsyncWaitHandle.WaitOne();
        // get number of bytes read on each cycle
        nBytesRead = net.EndRead(ar);

        // write partial content to file (synchronously)
        fs.Write(buffer,offset,nBytesRead);
        // update offset
        offset += nBytesRead;
    }
    while( nBytesRead > 0);
}

我的问题是,在问题陈述中,是这样说的:

The question I have is that, in the question statement, is said:

要进行传输,请使用异步读取和同步写入,避免一个线程在读取过程中被阻塞操作

To do the transfer, use asynchronous reads and synchronous writes, avoiding one thread to be blocked during read operations

我不确定我的解决方案是否能完成本练习中的要求,因为我使用 AsyncWaitHandle.WaitOne() 等待异步读取完成.

I'm not really sure if my solution accomplishes what is wanted in this exercise, because I'm using AsyncWaitHandle.WaitOne() to wait until the asynchronous read completes.

另一方面,我并没有真正弄清楚在这种情况下什么是非阻塞"解决方案,因为 FileStream 写入是同步进行的.. 要做到这一点,我必须等到 NetworkStream 读取完成才能继续编写 FileStream,不是吗?

On the other side, I'm not really figuring out what is meant to be a "non-blocking" solution in this scenario, as the FileStream write is meant to be made synchronously... and to do that, I have to wait until NetworkStream read completes to proceed with the FileStream writing, isn't it?

你能帮我解决这个问题吗?

Can you, please, help me out with this?

[ EDIT 1 ] 使用回调解决方案

[ EDIT 1 ] Using callback solution

好的,如果我理解 Mitchel Sellerswillvv 回答说,有人建议我使用回调方法将其转变为非阻塞"解决方案.这是我的代码,然后:

Ok, if I understood what Mitchel Sellers and willvv replied, I've been counseled to use a callback method to turn this into a "non-blocking" solution. Here is my code, then:

byte[] buffer; // buffer

public static void NetToFile(NetworkStream net, FileStream file) {
    // buffer with same dimension as file stream data
    buffer = new byte[file.Length];
    //start asynchronous read
    net.BeginRead(buffer,0,buffer.Length,OnEndRead,net);
}

//asynchronous callback
static void OnEndRead(IAsyncResult ar) {
    //NetworkStream retrieve
    NetworkStream net = (NetworkStream) ar.IAsyncState;
    //get number of bytes read
    int nBytesRead = net.EndRead(ar);

    //write content to file
    //... and now, how do I write to FileStream instance without
    //having its reference??
    //fs.Write(buffer,0,nBytesRead);
}

正如您可能已经注意到的,我被困在回调方法上,因为我没有对 FileStream 实例的引用,我想在其中调用Write(...)"方法.

As you may have noticed, I'm stuck on the callback method, as I don't have a reference to the FileStream instance where I want to invoke the "Write(...)" method.

此外,这不是线程安全的解决方案,因为 byte[] 字段是公开的,并且可能在并发的 NetToFile 调用之间共享.我不知道如何在不暴露外部作用域中的这个 byte[] 字段的情况下解决这个问题......而且我几乎可以肯定它可能不会以这种方式暴露.

Additionally, this is not a thread-safe solution, as the byte[] field is exposed and may be shared among concurrent NetToFile invocations. I don't know how to solve this problem without exposing this byte[] field in the outer-scope... and I'm almost sure it may not be exposed this way.

我不想使用 lambda 或匿名方法解决方案,因为这不在并发编程"课程的课程中.

I don't want to use a lambda or anonymous method solution, because that's not in the curriculum of "Concurrent Programing" course.

推荐答案

您将需要使用来自 NetStream 读取的回调来处理此问题.坦率地说,将复制逻辑包装到它自己的类中可能更容易,以便您可以维护活动流的实例.

You are going to need to use the callback from the NetStream read to handle this. And frankly it might be easier to wrap the copying logic into its own class so that you can maintain the instance of the active Streams.

这就是我的处理方式(未测试):

This is how I'd approach it (not tested):

public class Assignment1
{
    public static void NetToFile(NetworkStream net, FileStream file) 
    {
        var copier = new AsyncStreamCopier(net, file);
        copier.Start();
    }

    public static void NetToFile_Option2(NetworkStream net, FileStream file) 
    {
        var completedEvent = new ManualResetEvent(false);

        // copy as usual but listen for completion
        var copier = new AsyncStreamCopier(net, file);
        copier.Completed += (s, e) => completedEvent.Set();
        copier.Start();

        completedEvent.WaitOne();
    }

    /// <summary>
    /// The Async Copier class reads the input Stream Async and writes Synchronously
    /// </summary>
    public class AsyncStreamCopier
    {
        public event EventHandler Completed;

        private readonly Stream input;
        private readonly Stream output;

        private byte[] buffer = new byte[4096];

        public AsyncStreamCopier(Stream input, Stream output)
        {
            this.input = input;
            this.output = output;
        }

        public void Start()
        {
            GetNextChunk();
        }

        private void GetNextChunk()
        {
            input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null);
        }

        private void InputReadComplete(IAsyncResult ar)
        {
            // input read asynchronously completed
            int bytesRead = input.EndRead(ar);

            if (bytesRead == 0)
            {
                RaiseCompleted();
                return;
            }

            // write synchronously
            output.Write(buffer, 0, bytesRead);

            // get next
            GetNextChunk();
        }

        private void RaiseCompleted()
        {
            if (Completed != null)
            {
                Completed(this, EventArgs.Empty);
            }
        }
    }
}

这篇关于.NET 异步流读/写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆