使用 protobuf-net 进行惰性、流驱动的对象序列化

2024-01-05

我们正在开发一个用于流式传输大量数据的 WCF 服务,因此我们选择使用WCF 流式传输 http://msdn.microsoft.com/en-us/library/ms733742.aspx功能结合protobuf网络 http://code.google.com/p/protobuf-net/序列化。

Context:

一般来说,一个想法是序列化服务中的对象,将它们写入流中并发送。 在另一端,调用者将收到一个 Stream 对象,它可以读取所有数据。

所以目前服务方法代码看起来有点像这样:

public Result TestMethod(Parameter parameter)
{
    // Create response
    var responseObject = new BusinessResponse { Value = "some very large data"};

    // The resposne have to be serialized in advance to intermediate MemoryStream
    var stream = new MemoryStream();
    serializer.Serialize(stream, responseObject);
    stream.Position = 0;

    // ResultBody is a stream, Result is a MessageContract
    return new Result {ResultBody = stream};
}

BusinessResponse 对象被序列化为 MemoryStream 并从方法返回。 在客户端,调用代码如下所示:

var parameter = new Parameter();

// Call the service method
var methodResult = channel.TestMethod(parameter);

// protobuf-net deserializer reads from a stream received from a service.
// while reading is performed by protobuf-net, 
// on the service side WCF is actually reading from a 
// memory stream where serialized message is stored
var result = serializer.Deserialize<BusinessResponse>(methodResult.ResultBody);
return result;

So when serializer.Deserialize()被称为从流中读取methodResult.ResultBody,同时在服务端 WCF 正在读取 MemoryStream,该 Stream 已从TestMethod.

Problem:

我们想要实现的目标是摆脱MemoryStream并立即在服务端对整个对象进行初始序列化。 由于我们使用流式传输,因此我们希望避免在发送之前将序列化对象保留在内存中。

Idea:

完美的解决方案是返回一个空的、定制的 Stream 对象(来自TestMethod())以及对要序列化的对象的引用(在我的示例中为“BusinessResponse”对象)。 因此,当 WCF 调用Read()在我的流的方法中,我使用 protobuf-net 在内部序列化对象的一部分并将其返回给调用者,而不将其存储在内存中。

现在有一个问题,因为我们真正需要的是在读取流的那一刻能够将对象一块一块地序列化。 我知道这是完全不同的序列化方式 - 我不想将对象推送到序列化器,而是想逐个请求序列化内容。

使用 protobuf-net 是否可以实现这种序列化?


我编写了一些可能与 Marc 的门思想类似的代码。

public class PullStream : Stream
{
    private byte[] internalBuffer;
    private bool ended;
    private static ManualResetEvent dataAvailable = new ManualResetEvent(false);
    private static ManualResetEvent dataEmpty = new ManualResetEvent(true);

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    public override void Flush()
    {
        throw new NotImplementedException();
    }

    public override long Length
    {
        get { throw new NotImplementedException(); }
    }

    public override long Position
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        dataAvailable.WaitOne();
        if ( count >= internalBuffer.Length)
        {
            var retVal = internalBuffer.Length;
            Array.Copy(internalBuffer, buffer, retVal);
            internalBuffer = null;
            dataAvailable.Reset();
            dataEmpty.Set();
            return retVal;
        }
        else
        {
            Array.Copy(internalBuffer, buffer, count);
            internalBuffer = internalBuffer.Skip(count).ToArray(); // i know
            return count;
        }
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        dataEmpty.WaitOne();
        dataEmpty.Reset();

        internalBuffer = new byte[count];
        Array.Copy(buffer, internalBuffer, count);

        Debug.WriteLine("Writing some data");

        dataAvailable.Set();
    }

    public void End()
    {
        dataEmpty.WaitOne();
        dataEmpty.Reset();

        internalBuffer = new byte[0];

        Debug.WriteLine("Ending writes");

        dataAvailable.Set();
    }
}

这是一个简单的流后代类,仅实现读取和写入(和结束)。当没有数据可用时,读取会阻塞;当数据可用时,写入会阻塞。这样就只涉及一个字节缓冲区。其余的 linq 复制已开放以进行优化;-) 添加了 End 方法,因此在没有数据可用时执行 Read 时不会发生阻塞,并且不会再写入任何数据。

您必须从单独的线程写入此流。我在下面展示了这一点:

    // create a large object
    var obj = new List<ToSerialize>();
    for(int i = 0; i <= 1000; i ++)
        obj.Add(new ToSerialize { Test = "This is my very loooong message" });
    // create my special stream to read from
    var ms = new PullStream();
    new Thread(x =>
    {
        ProtoBuf.Serializer.Serialize(ms, obj);
        ms.End();
    }).Start();
    var buffer = new byte[100];
    // stream to write back to (just to show deserialization is working too)
    var ws = new MemoryStream();
    int read;
    while ((read = ms.Read(buffer, 0, 100)) != 0)
    {
        ws.Write(buffer, 0, read);
        Debug.WriteLine("read some data");
    }
    ws.Position = 0;
    var back = ProtoBuf.Serializer.Deserialize<List<ToSerialize>>(ws);

我希望这能解决您的问题:-) 无论如何,编写此代码很有趣。

问候, 雅科

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

使用 protobuf-net 进行惰性、流驱动的对象序列化 的相关文章

  • 注销租约抛出 InvalidOperationException

    我有一个使用插件的应用程序 我在另一个应用程序域中加载插件 我使用 RemoteHandle 类http www pocketsilicon com post Things That Make My Life Hell Part 1 App
  • C中的malloc内存分配方案

    我在 C 中尝试使用 malloc 发现 malloc 在分配了一些内存后浪费了一些空间 下面是我用来测试 malloc 的一段代码 include
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 获取两个工作日之间的天数差异

    这听起来很简单 但我不明白其中的意义 那么获取两次之间的天数的最简单方法是什么DayOfWeeks当第一个是起点时 如果下一个工作日较早 则应考虑在下周 The DayOfWeek 枚举 http 20 20 5B1 5D 3a 20htt
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 是否有实用的理由使用“if (0 == p)”而不是“if (!p)”?

    我倾向于使用逻辑非运算符来编写 if 语句 if p some code 我周围的一些人倾向于使用显式比较 因此代码如下所示 if FOO p some code 其中 FOO 是其中之一false FALSE 0 0 0 NULL etc
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • 如何检测表单的任何控件的变化?

    如何检测 C 中表单的任何控件的更改 由于我在一个表单上有许多控件 并且如果表单中的任何控件值发生更改 我需要禁用按钮 我正在寻找一些内置函数 事件处理程序 属性 并且不想为此创建自定义函数 不 我不知道任何时候都会触发任何事件any控制表
  • 如何在 32 位或 64 位配置中以编程方式运行任何 CPU .NET 可执行文件?

    我有一个可在 32 位和 64 位处理器上运行的 C 应用程序 我试图枚举给定系统上所有进程的模块 当尝试从 64 位应用程序枚举 32 位进程模块时 这会出现问题 Windows 或 NET 禁止它 我认为如果我可以从应用程序内部重新启动
  • C# 中的合并运算符?

    我想我记得看到过类似的东西 三元运算符 http msdn microsoft com en us library ty67wk28 28VS 80 29 aspx在 C 中 它只有两部分 如果变量值不为空 则返回变量值 如果为空 则返回默
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • 为什么 gcc 抱怨“错误:模板参数 '0' 的类型 'intT' 取决于模板参数”?

    我的编译器是gcc 4 9 0 以下代码无法编译 template
  • C++ 函数重载类似转换

    我收到一个错误 指出两个重载具有相似的转换 我尝试了太多的事情 但没有任何帮助 这是那段代码 CString GetInput int numberOfInput BOOL clearBuffer FALSE UINT timeout IN
  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • WebSocket安全连接自签名证书

    目标是一个与用户电脑上安装的 C 应用程序交换信息的 Web 应用程序 客户端应用程序是 websocket 服务器 浏览器是 websocket 客户端 最后 用户浏览器中的 websocket 客户端通过 Angular 持久创建 并且
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐

  • 使用 QIODevice 的阻塞接口(QTcpSocket 和 QFile)时何时检查错误

    出于学习目的 我制作了通过网络发送文件的应用程序 这对我来说非常有效 这里我将发布主要部分的代码 实际发送字节的代码 我认为这就足够了 我的主要问题是 我应该何时 何地 为何以及如何检查错误 看起来不止一个问题 正如您所看到的 我通过检查每
  • 选择显示输入 AngularJS 中的值

    我需要做这样的事情 当你选择 ex 登录 然后在输入文本中显示login from scope logins与password JS scope logins login log password pass HTML
  • 在java中展平嵌套数组

    我想展平嵌套数组 例如 1 2 3 4 gt 1 2 3 4 在java中手动我找不到线索 S 我尝试过手动java脚本指南 但没有得到解决方案 public static void main String args Object arr
  • 如何在 next.js 中使用 tailwind 背景图片? [复制]

    这个问题在这里已经有答案了 我在公共文件夹中有一张背景图片 名为bg png 在页面文件夹的index js页面中 我想使用该图像作为背景图像 我已经按照他们的官方网站的文档安装了 tailwind 我已经尝试过这个 但它不起作用 从 pu
  • 获取 Twitter API 搜索结果的关注者数量

    我想做的是提取一些搜索结果 并按用户对它们进行排序 现在我正在使用 to gt OAuthRequest http search twitter com search json http search twitter com search
  • 在索引页面上设置 PHP 会话以进行 XSRF 检查

    我遇到了以下有关 XSRF 令牌的问题 客户端 AngularJS 服务器 PHP 当index php被点击时 PHP生成一个XSRF令牌并将其保存在会话中 cookie 设置为相同的值 AngularJS 读取 cookie 并存储值
  • 如何创建带有图像和文本的按钮

    Friends 我想在 android 中显示一个按钮 如屏幕截图中提到的 谁能指导我如何实现这一目标 使用普通按钮drawableLeft属性 看我的示例代码
  • EmberJS pre2 将车把模板放在错误的位置

    我尝试在我的网络应用程序上将 EmberJS 从 pre1 更新到 pre2 但我注意到它将所有车把模板作为最后一个主体元素 有时根本不这样做 I ve 创建一个重现 http emberjs pre2 bug staticloud com
  • 有什么办法可以等到 DirectionsService 返回结果吗?

    我在使用 Google DirectionsService 时遇到问题 我知道它是异步的 这就是我遇到麻烦的原因 我想等到 DirectionsService 返回结果 而不是在没有答案的情况下执行代码 这是一个示例 function sn
  • 如何在集成测试中传递授权令牌标头?

    A 相关问题 https stackoverflow com questions 12041091 ror testing an action that uses http token authentication意味着我可以使用令牌身份验
  • Linux进程间通信如何选择“Key”?

    再会 我正在做作业 其中指出我有 5 个进程 一个服务器 其余的都是客户端 每个进程都应该由不同的可执行文件引发 我将实现一个双向消息传递解决方案 但问题不在于消息传递本身 有没有一种优雅的方式来传达key这些不同的可执行文件之间 即当我调
  • 递增指针 (ptr++) 和 (*ptr++)

    当我有这个疑问时 我正在重新审视指针 int ptr int arr 5 10 20 30 40 50 ptr arr 0 Now printf Value d ptr 会打印10 if I do ptr printf Value d pt
  • 我如何告诉 R 正确舍入?

    我如何告诉 R 正确舍入 R 中的小数位数 我遇到了一个不知道如何解决的问题 我希望 R 计算 5 26 100 19 230769 x lt 5 26 100 x 给我 1 19 23077 让我们尝试使用 round 首先将数字设置为
  • 通过 pyCurl 上传文件

    我正在尝试将以下curl代码转换为pycurl 我不想使用请求 我需要使用 pycurl 因为 requests 在我的旧 python 版本中不能完全工作 curl X POST H Accept Language en F email
  • 如何将 amazon S3 存储桶策略设置为除管理员之外的所有人私有?

    我有一个存储桶 我不小心将数千个带有 ACL 的文件上传到 public read 我希望除生成的访问 URL 之外的所有文件均不可用 我尝试创建一个存储桶策略 拒绝所有人的所有操作 并允许我的所有操作 它不起作用 即使生成了访问 URL
  • 将 DataTable 转换为 XML 文件,反之亦然

    我在将 XML 文件读取到DataTable 最初 我正在写一个Datatable到 XML 文件并保存 现在 当我想将 XML 文件读回到DataTable 它没有发生 以下代码用于写入文件 private void saveAsTool
  • Elastic Search:具有自定义类型的一个索引来区分文档模式 VS 多个索引,每个文档类型一个索引?

    我在 ES 方面没有经验 我的背景更多是关系数据库 我试图实现在我的 Web 应用程序中拥有一个搜索栏来搜索它的全部内容 或者我愿意索引的内容 的目标英语 实现的架构是 Jamstack 其中 gatsby 应用程序从 Strapi 应用程
  • 错误:“无法分配给‘Bool’类型的不可变表达式”?

    我该如何解决 我是一名新编码员 谢谢 我收到以下错误 无法分配给 Bool 类型的不可变表达式 当我尝试将 isSelected 设置为false and true IBAction func onFilter sender Any if
  • 使用 Sympy 方程进行绘图

    创建 Sympy 方程 求导 然后绘制该方程的结果的最佳方法是什么 我有符号方程 但无法弄清楚如何制作用于绘图的值数组 这是我的代码 from sympy import symbols import matplotlib pyplot as
  • 使用 protobuf-net 进行惰性、流驱动的对象序列化

    我们正在开发一个用于流式传输大量数据的 WCF 服务 因此我们选择使用WCF 流式传输 http msdn microsoft com en us library ms733742 aspx功能结合protobuf网络 http code