.NET 异步流读/写

2023-11-29

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

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

void NetToFile(NetworkStream net, FileStream file);

我一直在尝试解决这个练习,但我正在努力解决与问题本身相关的问题。但首先,这是我的代码:

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);
}

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

要进行传输,请使用异步 读取和同步写入,避免 一个线程在读取期间被阻塞 运营

我不太确定我的解决方案是否实现了本练习中所需的效果,因为我正在使用AsyncWaitHandle.WaitOne()等待异步读取完成。

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

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


[编辑1]Using callback解决方案

好吧,如果我明白的话米切尔·塞勒斯 and willvv回答说,有人建议我使用回调方法将其变成“非阻塞”解决方案。这是我的代码:

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(...)”方法的实例。

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

我不想使用 lambda 或匿名方法解决方案,因为这不在“并发编程”课程的课程内容中。


尽管帮助人们完成家庭作业有悖常理,但考虑到这已经有一年多了,以下是实现这一目标的正确方法。所有你需要的overlap您的读/写操作 - 不需要产生额外的线程或任何其他操作。

public static class StreamExtensions
{
    private const int DEFAULT_BUFFER_SIZE = short.MaxValue ; // +32767
    public static void CopyTo( this Stream input , Stream output )
    {
        input.CopyTo( output , DEFAULT_BUFFER_SIZE ) ;
        return ;
    }
    public static void CopyTo( this Stream input , Stream output , int bufferSize )
    {
        if ( !input.CanRead ) throw new InvalidOperationException(   "input must be open for reading"  );
        if ( !output.CanWrite ) throw new InvalidOperationException( "output must be open for writing" );

        byte[][]     buf   = { new byte[bufferSize] , new byte[bufferSize] } ;
        int[]        bufl  = { 0 , 0 }                                       ;
        int          bufno = 0 ;
        IAsyncResult read  = input.BeginRead( buf[bufno] , 0 , buf[bufno].Length , null , null ) ;
        IAsyncResult write = null ;

        while ( true )
        {

            // wait for the read operation to complete
            read.AsyncWaitHandle.WaitOne() ; 
            bufl[bufno] = input.EndRead(read) ;

            // if zero bytes read, the copy is complete
            if ( bufl[bufno] == 0 )
            {
                break ;
            }

            // wait for the in-flight write operation, if one exists, to complete
            // the only time one won't exist is after the very first read operation completes
            if ( write != null )
            {
                write.AsyncWaitHandle.WaitOne() ;
                output.EndWrite(write) ;
            }

            // start the new write operation
            write = output.BeginWrite( buf[bufno] , 0 , bufl[bufno] , null , null ) ;

            // toggle the current, in-use buffer
            // and start the read operation on the new buffer.
            //
            // Changed to use XOR to toggle between 0 and 1.
            // A little speedier than using a ternary expression.
            bufno ^= 1 ; // bufno = ( bufno == 0 ? 1 : 0 ) ;
            read = input.BeginRead( buf[bufno] , 0 , buf[bufno].Length , null , null ) ;

        }

        // wait for the final in-flight write operation, if one exists, to complete
        // the only time one won't exist is if the input stream is empty.
        if ( write != null )
        {
            write.AsyncWaitHandle.WaitOne() ;
            output.EndWrite(write) ;
        }

        output.Flush() ;

        // return to the caller ;
        return ;
    }


    public static async Task CopyToAsync( this Stream input , Stream output )
    {
        await input.CopyToAsync( output , DEFAULT_BUFFER_SIZE ) ;
        return;
    }

    public static async Task CopyToAsync( this Stream input , Stream output , int bufferSize )
    {
        if ( !input.CanRead ) throw new InvalidOperationException( "input must be open for reading" );
        if ( !output.CanWrite ) throw new InvalidOperationException( "output must be open for writing" );

        byte[][]     buf   = { new byte[bufferSize] , new byte[bufferSize] } ;
        int[]        bufl  = { 0 , 0 } ;
        int          bufno = 0 ;
        Task<int>    read  = input.ReadAsync( buf[bufno] , 0 , buf[bufno].Length ) ;
        Task         write = null ;

        while ( true )
        {

            await read ;
            bufl[bufno] = read.Result ;

            // if zero bytes read, the copy is complete
            if ( bufl[bufno] == 0 )
            {
                break;
            }

            // wait for the in-flight write operation, if one exists, to complete
            // the only time one won't exist is after the very first read operation completes
            if ( write != null )
            {
                await write ;
            }

            // start the new write operation
            write = output.WriteAsync( buf[bufno] , 0 , bufl[bufno] ) ;

            // toggle the current, in-use buffer
            // and start the read operation on the new buffer.
            //
            // Changed to use XOR to toggle between 0 and 1.
            // A little speedier than using a ternary expression.
            bufno ^= 1; // bufno = ( bufno == 0 ? 1 : 0 ) ;
            read = input.ReadAsync( buf[bufno] , 0 , buf[bufno].Length );

        }

        // wait for the final in-flight write operation, if one exists, to complete
        // the only time one won't exist is if the input stream is empty.
        if ( write != null )
        {
            await write;
        }

        output.Flush();

        // return to the caller ;
        return;
    }

}

Cheers.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

.NET 异步流读/写 的相关文章

  • 如何通过ConfigurationManager找到配置文件位置?

    如何通过ConfigurationManager找到配置文件位置 我在代码中有 ConfigurationManager 类 并且正在调试它 我想知道它指向哪个配置文件 web config 或 app config 等 Configura
  • YouTube 播放器 API:getDuration()、getCurrentTime()、getVideoData() 不起作用

    对于我的应用程序 我尝试使用 YouTube Iframe 播放器 API 来播放视频 并允许用户更改视频而无需重新加载页面 我通过使用来实现这一点player loadVideoById video id 方法 通过YouTube视频id
  • C++0x 初始值设定项列表示例

    我想看看这个现有代码示例如何利用 C 0x 初始化列表功能 示例0 include
  • 是否有可能将 *.pdb 文件包含到发布版本中以查看错误行号?

    我做了一个项目 所有设置都是默认的 当我在调试模式 构建配置 调试 下运行它并遇到异常时 它转储到我的自定义日志记录机制 其中包含错误行号 但是当我运行发布构建时 记录相同的异常 没有行号 只有方法抛出和记录调用堆栈 是否有可能在发布配置
  • 在异步请求中使用超时回调

    我之前问过这个问题 但我将用提出的解决方案来完成这个问题 并提出另一个问题 我正在使用这个类来进行异步网络请求 http msdn microsoft com en us library system net webrequest aspx
  • C#生成的csv文件通过电子邮件发送嵌入到Lotus Note中电子邮件的底部

    我遇到了一个奇怪的问题 即使用 NET SmtpClient 通过电子邮件发送的 CSV 附件出现在电子邮件底部 而不是 Lotus Note 中的附件 我只是不知道如何解决这个问题 而且我无法访问客户端计算机 这使得调试非常困难 我可以采
  • 为什么 rand() 总是返回相同的值? [复制]

    这个问题在这里已经有答案了 可能的重复 在C中生成随机数 https stackoverflow com questions 3067364 generating random numbers in c 使用 rand 生成随机数 http
  • 使用 catch all 字典属性将 json 序列化为对象

    我想使用 JSON net 反序列化为对象 但将未映射的属性放入字典属性中 是否可以 例如给定 json one 1 two 2 three 3 和 C 类 public class Mapped public int One get se
  • Web 文本编辑器中的 RTF 格式

    网络上是否有支持 RTF 格式文档输入的文本编辑器 我知道这对 webdev 来说有点奇怪 但我需要从数据库中读取 RTF 文档 并在基于 Web 的文本编辑器中对其进行编辑 然后将其存储回 RTF 中 在我在转换工具上投入太多资金之前 我
  • 重定向 std::cout

    我需要一个类 在其对象的生命周期内将一个 ostream 重定向到另一个 ostream 经过一番修补后 我想出了这个 include
  • 如何解决文件被另一个进程使用的问题?

    我一直在 VS NET 2010 中调试 没有任何问题 但现在无法建造 我收到错误 Unable to copy file filename to bin Debug filename The process cannot access t
  • 使用联合对 IP 地址进行多种解释?

    在工作中 我们使用以下构造来将 IP 地址解释为 4 字节数组或 32 位整数 union IPv4 std uint32 t ip std uint8 t data 4 这很好用 但是读完这本书的第 97 章 不要使用联合来重新解释表示
  • 如何在 ASP.NET Core 项目中使用 MStest 测试 Ok() 结果

    我正在使用 MStest 来测试我的控制器 我想测试这个动作 HttpGet Name GetGroups public async Task
  • 模板定义中的友元函数

    我的问题有点相关this https stackoverflow com questions 1297609 overloading friend operator for template class one 我想重载某些类的运算符 te
  • 如何在 SQLite 中检查数据库是否存在 C#

    我目前正在用 C 编写一个应用程序 并使用 sqlite 作为嵌入式数据库 我的应用程序在启动时创建一个新数据库 但如何让它检查数据库是否存在 如果它确实存在 我如何让它使用它 如果不存在如何创建一个新数据库 这是我到目前为止所拥有的 pr
  • 如何使 WinForms UserControl 填充其容器的大小

    我正在尝试创建一个多布局主屏幕应用程序 我在顶部有一些按钮链接到应用程序的主要部分 例如模型中每个实体的管理窗口 单击这些按钮中的任何一个都会在面板中显示关联的用户控件 面板包含用户控件 而用户控件又包含用户界面 WinForms User
  • 在 C# 窗口应用程序中运行 C/C++ 控制台应用程序?

    现在 我想开发一个简单的应用程序 因此我决定最快的编码方式是 C NET 但现在 我很难实现我需要的功能之一 我想做的是在 C 应用程序的窗口内运行 C C 控制台应用程序 就像在虚幻前端中一样 添加一点通信方式 以便我可以为控制台应用程序
  • 如何获取运行或段落的高度

    我找到了Run or Paragraph in FlowDocument现在我需要知道HEIGHT of it i e while navigator CompareTo flowDocViewer Document ContentEnd
  • execlp() 系统调用输出错误

    这个非常简单的例子exec 系统调用 在这里 我试图打电话execlp 两次 但是 我没有得到例外的输出 它仅显示当前目录的第一次调用的输出 include
  • 查找和替换正则表达式问题

    感谢这里对我其他问题的所有大力帮助 我开始掌握正则表达式 但我仍然对这个一无所知 我的代码是 StreamReader reader new StreamReader fDialog FileName ToString string con

随机推荐

  • ng-repeat 动画不起作用

    我的 ng repeat 动画似乎不起作用 这是笨蛋 http plnkr co edit kYtzM9d0rzGmrniybz9c p preview 任何输入 1 您已注册两个模块 And Remove ng app来自 html 标签
  • 按钮悬停颜色更改动画 c#

    我创建了一个 Windows 窗体 它有 3 个按钮 因此 我想通过使用 mouseenter 事件来更改颜色的一键式按钮 工作正常 但我需要通过淡入或淡出的过渡来改变颜色 任何对此问题有答案的人请告诉我下面的代码 我将向您展示我的 mou
  • 通过 aws.push 部署到 Elastic Beanstalk 时保留某些现有文件

    我们在 EC2 服务器上的应用程序目录中有 SOLR 而不是在本地 git 存储库中 当我们将本地存储库推送到 EC2 时 它会删除 Solr 目录 我们已将目录名称放入 gitignore 文件中 但它仍然覆盖 SOLR 目录 我们如何防
  • IE 7 CTRL + 单击打开一个新窗口 - 如何抑制它?

    Is it possible to suppress the default IE 7 functionality when CTRL click on link opens a new window if so how Thanks Th
  • 如何在 SQL Server 2008 中从 IP 地址获取计算机名称?

    我必须从 SQL Server 中的 IP 地址获取计算机名称 我可以做些什么来完成我的任务 DB IPAdd MachineName Query select MachineName from DBTable where IPAdd yo
  • 在安卓中搜索

    我有一个应用程序 我希望在其中添加搜索功能 我正在尝试按照中所述实施developer android但是当我单击模拟器中的搜索时 活动没有启动 问题是什么 SearchActivity java public class SearchAc
  • 在 Spring Boot 中禁用自动日志记录配置

    我使用 spring boot 1 2 1 RELEASE 并注意到 spring 在启动时自动更改我的 log4j 配置 这是我的 春季 依赖项
  • 用于设置类的 CKEditor 插件

    我想做的是类似于本机前景色 背景颜色对话框 不同之处在于 它将直接在工具栏中包含带有颜色的按钮 所以一个插件必须有多个按钮 具有不同的样式 颜色 另一个问题是 这个原生插件设置了 CSScolor and background color特
  • 什么是“装饰器”以及它们如何使用?

    我很好奇 AngularJS 中的装饰器到底是什么 除了装饰器中的简介之外 网上没有太多关于装饰器的信息AngularJS 文档并在一个简短的 尽管有趣的 提及Youtube 视频 正如 Angular 的人所说 装饰器是 服务的装饰 允许
  • 音频和视频等大文件的数据库

    我的应用程序创建了大量文件 每个文件最大 100MB 目前我们将这些文件存储在运行良好的文件系统中 但我想知道是否有更好的解决方案将文件存储在某种文件数据库中 数据库的一个简单优点是它可以分割文件并存储在小块中 而不是一个 100mb 的文
  • 使用 shebang 通过 subprocess.call 执行 python 脚本

    我正在用 Python 3 编写一个 某种程度上 模块化应用程序 我想从中运行任意程序 该程序是在运行时指定的 而不一定是 python 脚本 所以我用例如 subprocess call spam i eggs o ham If spam
  • 带有自定义标签的 CSS 宽度

    我无法获取适用于我的自定义标签的宽度和高度属性 请参阅下面的代码 CSS x slider width 1000px height 300px border 1px black solid background color 0000ff H
  • 在.NET中获取用户的Exchange服务器和电子邮件地址

    嗨 我想知道我的用户的 Exchange 服务器的地址 假设她位于典型的 Windows 办公网络中 这是在 C 应用程序中 我已经有了用户的电子邮件地址 我在以下位置找到了它System DirectoryServices Account
  • 类依赖工具

    我正在寻找一个 最好是开源 工具 在给定大量 C C 代码的情况下 该工具将生成类 C 和 或文件 C 之间依赖关系的可视化或 XML 图表 这个想法是 如果您必须将代码转换为另一种语言 您希望能够首先编译最低级别的类 然后从那里开始构建
  • 在 Apache Flink 中使用 DynamoDB 流

    有人尝试过在 Apache Flink 中使用 DynamoDB 流吗 Flink 有一个 Kinesis 消费者 但我正在寻找如何直接使用 Dynamo 流 DataStream
  • Windbg:是否可以在我自己的程序中嵌入Windgb引擎?

    我想编写一个调试 诊断工具 它可以调用 Windbg 函数来检查转储文件 而不是编写 Windbg 扩展 这可能吗 有什么参考吗 多谢 您可以使用 dbghelp dll 中实现的调试 API 而不是 WinDbg 它记录在MSDN 该参考
  • 用指针修改字符串[重复]

    这个问题在这里已经有答案了 这两个代码必须改变字符2在角色中 4 int main int argc char argv char s hello s 2 4 printf s n s return 0 当我运行此命令时 我会遇到分段错误
  • Python 和 MySQLdb:表替换导致语法错误

    我需要时不时地动态更改表和变量 所以我写了一个像这样的python方法 selectQ SELECT FROM s WHERE s s self db execute selectQ self table self columnSpecNa
  • F# 中“>>”运算符的语义

    在微软的F 样本 他们使用 gt gt 运算符 如下所示 test gt Seq iter any to string gt gt printfn line s gt gt 运算符在这种情况下做什么 序列中的每个项目 在本例中为数组 是否被
  • .NET 异步流读/写

    我一直在尝试解决这个 并发编程 考试练习 C 知道Stream类包含int Read byte buffer int offset int size and void Write byte buffer int offset int siz