【发布时间】: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