【问题标题】:C# Best way to transfer Serialized Protobuff data thru httpC# 通过 http 传输序列化 Protobuf 数据的最佳方式
【发布时间】:2018-02-23 12:44:05
【问题描述】:

我正在使用 Marc Gravell 的 Protobub-Net 来序列化和反序列化对象。

我正在寻找通过http:// 请求传输数据的最有效方式。

这是我到目前为止所做的:

public string ProtobuffToString()
{
    Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
    List1.Add(2018, 1.2m);
    List1.Add(2017, 1.4m);
    List1.Add(2016, 1.9m);

    using (var stream = new MemoryStream())
    {
         ProtoBuf.Serializer.Serialize(stream, List1);
        return Convert.ToBase64String(stream.ToArray());
    }
}

public async System.Threading.Tasks.Task<string> ReadProtobuffAsync()
{
    using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
    using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
    using (System.Net.Http.HttpContent content = response.Content)
    {
        string result = await content.ReadAsStringAsync();
        byte[] resultByte = Convert.FromBase64String(result);

        using (var stream = new MemoryStream(resultByte))
        {
            return JsonConvert.SerializeObject(ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(stream));
        }
    }
}

我可以做得更好吗?

比从 json/Json.Net 传输它更好/更快吗?

也许是的,因为数据传输会更小,序列化/反序列化更快。

【问题讨论】:

  • 按原样写入响应即可,无需转换为字符串。
  • 最高效的定义是什么?你如何评价这个,你用什么样的指标来判断它
  • 您可以直接在请求和响应中写入和读取二进制流。 Base64 编码完全没有必要。

标签: c# .net protobuf-net data-transfer-objects


【解决方案1】:

我可以做得更好吗?

Protobuf 是一种二进制序列化格式,针对(反)序列化和低占用空间传输进行了优化。通过将数据转换为 Base64,您可以添加另一个转换层并增加传输的占用空间。

比从 json/Json.Net 传输它更好/更快吗?

没有任何合理的论据可以支持这种说法。重申我之前的说法,Protobuf 是高度优化的,而 JSON 是一种折衷方案,序列化效率不高,可读性也不好。

话虽如此,举个小例子,如何通过 HTTP 发送您的 Protobuf

HttpClient client = new HttpClient();
using (var stream = new MemoryStream())
{
    // serialize to stream
    ProtoBuf.Serializer.Serialize(stream, List1);
    stream.Seek(0, SeekOrigin.Begin);

    // send data via HTTP
    StreamContent streamContent = new StreamContent(stream);
    streamContent.Headers.Add("Content-Type", "application/octet-stream");
    var response = client.PostAsync("http://what.ever/api/upload", streamContent);
}

如果你想接收 Protobuf,你可以修改你的 sn-p 喜欢

using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
using (System.Net.Http.HttpResponseMessage response = await client.GetAsync("http://localhost:53204/ProtobuffToString")) //<= Will call ProtobuffToString() above
using (System.Net.Http.HttpContent content = response.Content)
using (var memoryStream = new MemoryStream())
{
    await content.CopyToAsync(memoryStream);
    memoryStream.Seek(0, SeekOrigin.Begin); // reset stream

    return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(memoryStream); // assuming that you return the Dictionary, not a string
}

实际上,我不明白您为什么要从 ReadProtobuffAsync 返回 string 而不是 Dictionary&lt;int, decimal&gt;。我建议完全放弃 Dictionary 并使用有意义的 protobuf 定义和相应的类,因为这是 Protobuf 的真正优势。

【讨论】:

    【解决方案2】:

    问题和答案是主观的,完全基于“最佳”的定义。我确实看到了很多不必要的“额外”代码。我建议你直接使用 Streams,不需要先去内存流或转换为 base64 或转换为 json。如果您确实需要字符串表示,请在另一个实用程序方法中执行,而不是将其包装在此代码中。

    编写代码

    // depending on where you want to write to pass an appropriate Stream like a stream to write directly to an HttpPost or File on disk,
    // there is no need to write to memory
    public void SerializeToStream(Stream destinationStream)
    {
        Dictionary<int, decimal> List1 = new Dictionary<int, decimal>();
        List1.Add(2018, 1.2m);
        List1.Add(2017, 1.4m);
        List1.Add(2016, 1.9m);
    
        ProtoBuf.Serializer.Serialize(destinationStream, List1);
    }
    

    阅读代码

    public async System.Threading.Tasks.Task<Dictionary<int, decimal>> ReadProtobuffAsync()
    {
        using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
        using (System.IO.Stream responseStream = await client.GetStreamAsync("http://localhost:53204/ProtobuffToString"))
        {
            // deserialize directly from the response stream
            return ProtoBuf.Serializer.Deserialize<Dictionary<int, decimal>>(responseStream));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-26
      • 2011-10-26
      • 2017-03-02
      • 2010-12-27
      • 2023-02-02
      相关资源
      最近更新 更多