【问题标题】:Getting error: Protocol message contained an invalid tag (zero) despite bytes being exactly the same出现错误:协议消息包含无效标签(零),尽管字节完全相同
【发布时间】:2021-12-19 10:58:05
【问题描述】:

我正在尝试从 C# 中的 byte[] 反序列化我的 protobuf 数据。数据来自命名管道上的另一个 C++ 程序。我在两端打印字节(或无符号字符)数组,数组的字节和长度完全相同。尽管我在尝试反序列化数据时遇到了无效标记(零)错误。相关的代码部分是:

从 C++ 发送数据:

bool writeOutputMessage(HANDLE hPipe, const CubesExample::OutputMessage& outputMessage)
{
    int messageBytes = outputMessage.ByteSizeLong();
    char buffer[messageBytes + 4];
    outputMessage.SerializeToArray(&buffer + 4, messageBytes);
    memcpy(buffer, &messageBytes, 4);
    messageBytes += 4;

    DWORD bytesWritten = 0;
    std::cout << std::string("Writing ") + std::to_string(messageBytes) + " bytes" << std::endl;
    
    std::cout << "Sending bytes";
    for(char c : buffer) std::cout << " " << +static_cast<unsigned char>(c);
    std::cout << std::endl;

    BOOL fSuccess = WriteFile(
        hPipe,        // handle to pipe
        buffer,     // buffer to write from
        messageBytes, // number of bytes to write
        &bytesWritten,   // number of bytes written
        NULL);        // not overlapped I/O
    if (!fSuccess || bytesWritten != messageBytes)
    {
        std::cout << "InstanceThread WriteFile failed, GLE=" << GetLastError() << std::endl;
        return false;
    }

    return true;
}

在 C# 中接收数据:

public byte[] readOutputMessage()
{
    int readBytes = 0;
    byte[] messageSizeBuf = new byte[4];

    readBytes = fromagent_pipe.Read(messageSizeBuf, 0, 4);
    if(readBytes != 4)
    {
        Debug.Log("Failed to read message size!");
        return null;
    }
    int messageSize = BitConverter.ToInt32(messageSizeBuf, 0);

    Debug.Log("Attempting to read message of size: " + messageSize);
    byte[] buffer = new byte[messageSize];
    readBytes = 0;
    readBytes = fromagent_pipe.Read(buffer, 0, messageSize);
    if(readBytes != messageSize)
    {
        Debug.Log("Read " + readBytes + " bytes but expected " + messageSize);
        return null;
    }

    return buffer;
}

在 C# 中解析字节:

byte[] buffer = inputTask.Result;

string bytes = "";
foreach(byte b in buffer) bytes += " " + (uint)b;
Debug.Log("Got bytes: " + bytes + " Length: " + buffer.Length);

if(buffer != null)
{
    OutputMessage outputMessage = OutputMessage.Parser.ParseFrom(buffer);
    inputMotion = new UnityEngine.Vector2(outputMessage.MovementDirection.XPos, outputMessage.MovementDirection.YPos);
}

另外,这里是 C++ 进程的输出:

Writing 11 bytes
Sending bytes 7 0 0 0 227 0 0 0 72 57 201

以及来自 C# 进程的输出:

Attempting to read message of size: 7
Got bytes:  227 0 0 0 72 57 201 Length: 7

写入过程写入 4 个字节,指示消息的大小,然后是消息字节。在这种情况下,消息大小为 7,因此写入过程总共写入了 11 个字节。

如您所见,字节完全相同,但对OutputMessage.Parser.ParseFrom(buffer) 的调用仍然失败,标签无效(零)。

我错过了什么?

感谢任何提前阅读的人。

编辑: 发送的消息正在创建如下:

CubesExample::OutputMessage outputMessage; 
CubesExample::Vector2* moveDir = outputMessage.mutable_movementdirection(); 
moveDir->set_xpos(1.0f); 
moveDir->set_ypos(0.0f);

【问题讨论】:

  • 您发送的数据全是零,看起来有点滑稽。您的消息中包含哪些数据类型?当我尝试使用在线 protobuf 反序列化器反序列化数据时,我什么也得不到。这可能是由于数据无效。
  • OutputMessage 有一个 Vector2 消息,里面有 2 个浮点数。这就是我创建消息的方式: CubesExample::OutputMessage outputMessage; CubesExample::Vector2* moveDir = outputMessage.mutable_movementdirection(); moveDir->set_xpos(1.0f); moveDir->set_ypos(0.0f);
  • 浮点数是 4 个字节长,每个字段需要一个至少一个字节的标签。所以看起来你缺少三个字节。
  • outputMessage.ByteSizeLong() 不断返回 7。你知道为什么吗?
  • 我将浮点数从 1.0f、0.0f 更改为 1.0f、2.0f,消息大小增加到 12 个字节。当浮点值为 0.0f 时似乎有一个优化

标签: c# c++ protocol-buffers


【解决方案1】:

SerializeToArray() 中的错字。而不是:

outputMessage.SerializeToArray(&buffer + 4, messageBytes);

应该是:

outputMessage.SerializeToArray(buffer + 4, messageBytes);

:D

【讨论】:

    猜你喜欢
    • 2014-12-23
    • 1970-01-01
    • 2023-01-09
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-27
    • 1970-01-01
    相关资源
    最近更新 更多