【问题标题】:transfer int over network通过网络传输 int
【发布时间】:2011-06-04 09:49:29
【问题描述】:

我是网络编程新手,所以我有一个问题:在我的情况下,在 C++ 和 C# 之间发送整数(假设 16 位整数,因为 32 存在“字节序”问题)安全吗?如何做到这一点?

在我的程序中,我将 int 转换为 char(我知道它低于 255)并发送它。但是,我想发送 32 个 int。我尝试使用协议缓冲区进行此操作。我在 C++ 中使用了 WriteVarint32,在 C# 中使用了 ProtoReader.ReadUInt32,但没有成功(C# 中的例外)。我认为在阅读this 后它会起作用。

您会这么好心并建议我在 C++ 和 C# 应用程序之间发送整数的正确方法吗?如果您向我解释了如何使用协议缓冲区(C# 中的 protobuf-net)来做到这一点,我会非常高兴。

【问题讨论】:

  • 那么为什么 16 位没有字节序问题而 32 位有问题呢? 16 位在 bigendian/littleendian 机器中会有所不同。我建议您决定一种方法(例如协议缓冲区)并尝试它,并询问您遇到的问题。
  • @David varint 编码围绕字节顺序工作(它是隐式的)

标签: c# c++ network-programming protocol-buffers protobuf-net


【解决方案1】:

基本上,这将取决于您使用的网络库以及它们在两端的兼容性。在最低级别,数据以流或字节块的形式传输。当这些字节被转换回一个字节(甚至是 int)之上的任何更复杂的结构时,编码显然很重要并且需要在两端匹配。

最简单的事情就是试一试看看。

听起来您可能有兴趣尽可能紧密地打包数据(来自您对将整数转换为字符的评论),在这种情况下,您可能应该在任一端编写一组低级打包例程。这样你就不用担心编码了,你可以从数据包中挤出最后一点。

【讨论】:

    【解决方案2】:

    varint 编码没有字节序问题,它总是设计为小字节序。它从最低有效的七位开始,一次存储七位的值,当没有剩余一位时,使用第八位作为停止位。

    您使用 C# 中的 Read7BitEncodedInt 方法来读取 varint 编码的整数。

    【讨论】:

    • 我不确定,但似乎 Read7BitEncodedInt 在我使用的 MonoDevelop 中不可用。还有其他想法吗?
    • @lord-didger:在BinaryReader 类中。如果您正在使用其他方式读取数据,您可以轻松地为它修改代码,只需几行代码。你可以在这里找到源代码:koders.com/csharp/…
    【解决方案3】:

    如果您使用 protobuf-net 编写,WithLengthPrefix 方法将为您完成此操作。我很乐意为此提供帮助(我是作者)。顺便说一句,它引发异常的原因是 varint 值 本身 在 protobuf 流中通常无效。如果您将 0 作为字段编号传递(或者为更纯的 protobuf 流传递正的字段编号;但这是可选的),系统将在 WithLengthPrefix 的情况下覆盖它。

    碰巧在 ProtoReader 上有一个方法可以读取隔离的 varint(无需担心 protobuf 流语义),如果有用的话,我可以将其添加到 ProtoWriter 中。

    顺便说一句——就 PrefixStyle 而言,Base128 与 varint 相同。有些人更喜欢 32 位前缀,以便与其他系统结合 - 因此提供了一些其他系统。

    【讨论】:

    • 我想使用WithLengthPrefix。我的问题是我不知道我应该如何使用 C++ Protobuf API 来构造 C# protobuf-net 可以理解的前缀。 'Base128 与 varint 相同' - 我尝试发送带大小的 varint。 C# 引发 System.IO.EndOfStreamException。前缀是仅存在于 protobuf-net 中的想法。 C++ 实现甚至没有考虑与该概念类似的东西。
    • @lord - 确实如此。仅简要提及了此策略(在文档中),基本上说“添加您自己的长度”。关于 EOF - 我在之前的讨论中添加的 v2 示例中重新部署了 dll(我相信与你一起) - 检查你是否拥有当前版本。您能否简要介绍一下您的策略,即“我通过 C++ 发送的消息是 27 个字节,所以我写 [TODO: the bytes] 作为前缀,然后是 27 个字节” - 那么我应该能够看到你有什么。
    • 消息测试 { 需要 int32 id = 1;这就是我要发送的信息。现在我设置了 id (在 C++ 中): Test test; test.set_id(1234);我发送 Varint32 coded_output->WriteVarint32(test.ByteSize()); C# 应用程序应该准确接收这些字节(十六进制)03 08 d2 09。03 是大小,其余的是消息。目前,我很难将响应从 C# 发送回 C++。我相信我很快就会完成。
    • @lord - 碰巧的是,protobuf-net 将单个原语(int 等)视为字段 1 消息中的字段,因此 最小值得到它是int i = Serializer.DeserializeWithLengthPrefix<int>(source, PrefixStyle.Base128, 0)Serializer.SerializeWithLengthPrefix(ms, 1234, PrefixStyle.Base128, 0);(需要r404 dll,由于早期测试版中的一个错误)。您当然可以拥有一个带有 int 属性等的完整对象 - 这也可以正常工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多