【问题标题】:FlatBuffers: Encoding in C++ versus C#, decoding in C# end-to-end exampleFlatBuffers:C++ 与 C# 中的编码,C# 端到端示例中的解码
【发布时间】:2016-06-08 17:24:02
【问题描述】:

想象一个架构:

namespace MyEvents;  

table EventAddress  
{  
  id:uint;  
  timestamp:ulong;  
  adress:string;  
}  

table EventSignalStrength  
{  
  id:uint;  
  timestamp:ulong; 
  strength:float;   
}  

table EventStatus  
{  
  status:string;  
}  

union Events {EventAddress, EventSignalStrength, EventStatus}  

table EventHolder  
{  
  theEvent:Events;  
}  

root_type EventHolder;  

对于状态消息“EXIT”,在 C++ 中我编码并通过线路发送,如下所示:

std::string message("EXIT");  
flatbuffers::FlatBufferBuilder builder;  
auto messageString= builder.CreateString(message);  // Message to send.  
auto statusEvent= MyEvents::CreateEventStatus(builder, messageString);  
auto eventHolder= MyEvents::CreateEventHolder(builder, MyEvents::Events_EventStatus, statusEvent.Union());  
builder.Finish(eventHolder);  

// Code to decode to check my work omitted, but the data decode properly in my real-world application.  

ret= sendto(m_udpSocket, reinterpret_cast<const char*>(builder.GetBufferPointer()), static_cast<int>(builder.GetSize()), 0, reinterpret_cast<SOCKADDR *>(&m_destination), sizeof(m_destination));  

对于相同的消息“EXIT”,我在 C# 中编码并通过网络发送,如下所示:

string message= "EXIT";  
FlatBufferBuilder builder = new FlatBufferBuilder(1);  
StringOffset messageOffset = builder.CreateString(message);  
EventStatus.StartEventStatus(builder);  
EventStatus.AddStatus(builder, messageOffset);  
Offset<EventStatus> eventStatusOffset = EventStatus.EndEventStatus(builder);  

EventHolder.StartEventHolder(builder);  
EventHolder.AddTheEventType(builder, Events.EventStatus);  
EventHolder.AddTheEvent(builder, eventStatusOffset.Value);  
Offset<EventHolder> eventHolderOffset = EventHolder.EndEventHolder(builder);  

EventHolder.FinishEventHolderBuffer(builder, eventHolderOffset);  

// Test the encoding by decoding:  
EventHolder flatBuffer = EventHolder.GetRootAsEventHolder(builder.DataBuffer);  
Events flatBufferType = flatBuffer.TheEventType;  // Type looks good.  
EventStatus decodedEvent= new EventStatus();  
flatBuffer.GetDataObject<EventStatus>(decodedEvent);  // decodedEvent.Status looks good.  

// This code seems to send the correct data:  
Byte[] sendSized = builder.SizedByteArray();  
udpClient.Send(sendSized, sendSized.Length);  

// This code does not seem to send the correct data:  
//ByteBuffer sendByteBuffer = builder.DataBuffer;  
//udpClient.Send(sendByteBuffer.Data, sendByteBuffer.Data.Length);  

在我用 C# 编写的客户端应用程序中,我解码为:

Byte[] receiveBytes = udpClient.Receive(ref m_remoteEndpoint);  
ByteBuffer flatBufferBytes= new ByteBuffer(receiveBytes);  
EventHolder flatBuffer = EventHolder.GetRootAsEventHolder(flatBufferBytes);  
Events flatBufferType= flatBuffer.DataObjectType;  
EventAddress eventAddress = null;  
EventSignalStrength eventSignalStrength = null;  
EventStatus eventStatus = null;  
switch (flatBufferType)  
{  
  case Events.EventAddress:  
  {  
    eventAddress = new EventAddress();  
    flatBuffer.GetDataObject<EventAddress>(eventAddress);  
    ProcessEventAddress(eventAddress);  
    break;  
  }  

  case Events.EventSignalStrength:  
  {  
    eventSignalStrength = new EventSignalStrength();  
    flatBuffer.GetDataObject<EventSignalStrength>(eventSignalStrength);  
    ProcessEventSignalStrength(eventSignalStrength);  
    break;  
  }  

  case Events.EventStatus:  
  {  
    eventStatus= new EventStatus();  
    flatBuffer.GetDataObject<EventStatus>(eventStatus);  
    Console.WriteLine("\nStatus Message: {0}", eventStatus.status);  
    break;  
  }  
}  
  • 当我收到来自 C++ 应用程序的 EventStatus 消息时,它们会正确解码。
  • 当我收到来自 C# 发送应用程序的 EventStatus 消息时,它们会正确解码。
  • 当我转储从应用程序发送的缓冲区时,它们是(十进制):

  • C++ - 12 0 0 0 8 0 14 0 7 0 8 0 8 0 0 0 0 0 0 4 12 0 0 0 0 0 6 0 8 0 4 0 6 0 0 0 4 0 0 0 4 0 0 0 69 88 73 84 0 0 0 0

  • C# - 12 0 0 0 8 0 10 0 9 0 4 0 8 0 0 0 12 0 0 0 0 4 6 0 8 0 4 0 6 0 0 0 4 0 0 0 4 0 0 0 69 88 73 84 0 0 0 0

最初,来自 C# 发件人的消息没有正确解码 - 现在可以了。我对发件人进行了更改,所以可能没有重建。

  • 我有点疑惑,接收到的 C++ 缓冲区和 C# 缓冲区不同,但它们正确解码为相同的结果。
  • 我的实际架构要复杂得多 - 我是否遵循正确的 C# 端解码程序?
  • 我是否按照正确的程序将 flatbuffer 减少到 Byte[] 以便在 C# 中通过线路发送?看起来像我,但它似乎有一段时间没有工作......

任何意见表示赞赏。

【问题讨论】:

  • 我遇到了类似的问题,当从 C# 序列化时,我的缓冲区没有在 C++ 中反序列化。它可以在 C# 中反序列化。我可以知道你做了什么改变使它起作用吗?谢谢!
  • @GengyuShi - 我会试着看看我的工作代码,看看我做了什么。
  • @GengyuShi - 我很确定上面的简单示例设置正确。当我问这个问题时,我感到困惑的两件事是如何让字节缓冲区发送以及为什么原始数据 blob 不同。我之前在往返数据时遇到了问题,但已经修复了。我记得它只是对正在编码的数据进行了仔细分析。听起来您在 C++ 中的某个地方遗漏了一步 - 如果不查看您的架构和代码,很难知道是什么。我的生产代码对客户运行良好,我的 C# 示例客户端与 C++ 服务器运行良好。
  • 感谢@GTAE86。我的问题部分与额外的 C++ 端验证有关。我曾经让我的 C# 生产者的密钥类型为 long,但它不起作用。将其更改为 byte[] 并使用 BitConverter 进行字节转换就可以了,尽管在 C# 中它没有任何区别。

标签: c# c++ flatbuffers


【解决方案1】:

ByteBuffer 包含缓冲区,但不一定在偏移量 0,所以是的,将其转换为字节数组(或从其起始偏移量发送 bytebuffer 内容)是发送它的唯一正确方法。

不同语言的编码可能不同,因为实现可能以不同的顺序序列化事物。这里,C++实现决定在偏移前写联合类型字段,正好对齐效率低,所以就大了一点。 C# 则相反。

【讨论】:

  • 所以“把它变成一个字节数组”,你的意思是使用FlatBufferBuilder方法SizedByteArray()?要发送“从其起始偏移量开始的字节缓冲区内容” - 该偏移量是位置,对吧?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
  • 2019-06-01
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多