2

我遇到了一个有线问题,我正在使用 C# 的 protobuf-net 生成一个基于 Google Protocol Buffer 消息的文件,然后将其上传到我公司的一台服务器。

我在 C# 中创建了一个将 .proto 文件生成为 .cs 的工具,然后我使用它的类(来自 .cs 文件)来填充消息中的所有必填字段,然后我调用了 Serializer.Serialze() 函数它为我创建了请求的文件。

但是,这就是问题所在,我有另一个文件(相同的文件),它是在另一个用 C++ 编写的工具中创建的(使用与我使用的相同的 .proto 文件),但是当我尝试将我的文件上传到我们的服务器时我收到一个错误,表明有问题。

我将这两个文件与“Win Merge”软件进行了比较,我注意到与在 C++ 工具中生成的文件相比,3 个不同的行(每个文件中的 7000 多行)差别很小。

这是从 Win Merge 工具捕获的 2 行示例(左侧为 C++,右侧为 C#):

在此处输入图像描述

另一个例子:

我注意到差异在于矩形(我不明白这是什么意思)与它们里面的字节......

这是我正在使用的 .proto 文件:

message Package {

message ArchDepend {

    message Arch {
        required string version = 1;
        required string description = 2;
    }

    message Firmware {
        required string version = 1;
        required string description = 2;
        required bytes file = 3;

        repeated string from_version = 4;
    }

    message Rsu {
        required string version = 1;
        required string description = 2;
        required bytes file = 3;
    }

    required Arch arch = 1;

    optional Firmware firmware = 2;
    optional Rsu rsu = 3;
}

message DefaultEeprom {
    required string version = 1;
    required string description = 2;
    required bytes file = 3;

    message Migration {
        required string from_version = 1;
        required bytes file = 2;
    }

    repeated Migration migrations = 4;
}

required string name = 1;
optional ArchDepend archDepend = 2;
optional DefaultEeprom defaultEeprom = 3;

}

我在 .cs 文件中插入的字段是字符串,而 files(*.bin) 这里是字符串的示例:

“PowerMaster-30”

“JS702394 K17.A20”

ETC..

它们被插入到 .proto 文件中的大多数字符串字段中。

在文件字段 (.proto) 中,我正在加载我公司使用的二进制文件(与加载到 C++ 工具的文件相同)。

这是我正在从中读取数据的二进制文件的屏幕截图,在名为“Falsher.exe”的程序中打开,左侧转换为十六进制视图,右侧是 ASCII:

在此处输入图像描述

这是读取该二进制文件的代码:

       private string[] FindPanelVersionInBinFile(string path)
    {
        string currentline;
        int flag = 0;
        string[] namesArray = new string[3]; // contains all the strings which I get from the BIN file.

        using (StreamReader sr = new StreamReader(path))
        {
            while ((currentline = sr.ReadLine()) != null && flag < 3)
            {
                if (currentline.Contains("PRODUCT_FAMILY"))
                {
                    int index = currentline.IndexOf("PRODUCT_FAMILY");
                    namesArray[0] = currentline.Substring(index + 16, 14); // index of product family"PowerMaster-xx"
                    flag++;
                }
                if (currentline.Contains("SW_VERSION"))
                {
                    int index = currentline.IndexOf("SW_VERSION");
                    namesArray[1] = currentline.Substring(index + 12, 17); // index of software version "JSxxxxx Kxx.yyy"
                    flag++;                       
                }
                if (currentline.Contains("compatibility"))
                {
                    int index = currentline.IndexOf("compatibility");
                    namesArray[2] = currentline.Substring(index + 21, 7); // index of compatibility number "xx.yyy"
                    flag++;
                }                  
            }
        }
        return namesArray;

毕竟,我使用这段代码来生成我的文件:

                        byte[] data;
                        using (var ms = new MemoryStream())
                        {
                            Serializer.Serialize(ms, package);
                            data = ms.ToArray();
                        }
                        string packageFilePath = Path.Combine(savePath, package.Name);
                        File.WriteAllBytes(packageFilePath, data);

有人可以帮我解释一下到底有什么区别以及它们发生的原因是什么?

谢谢!!

猎户座。

4

1 回答 1

11

看起来区别只是以零结尾的字符串。

我猜(请纠正我)左边的数据来自 protobuf-net,右边的数据来自 C++ 实现。在左边我们有" [10],一些数据,然后[1A](我相信[1A]下一个字段标题:字段 3,以长度为前缀)。支持这个假设,/之前的“字符”(松散地说)是,即 ASCII 34 - (在 protobuf 中)表示“字段 2,长度前缀”。所以我很满意地告诉我们“字段 2,长度为 16 的字符串”,而告诉我们“字段 2,长度为 17 的字符串”。[10][11]"" [10]" [11]

因此,感觉 C# 中的字符串是 是合乎逻辑的"JS702415 K17.020",而 C++ 中的字符串是相同的,但带有一个 nul-terminator。这里很有趣:我不认为它应该包括 nul-terminator。所以:要么是 C++ API 犯了一个错误(我对此表示怀疑),要么在将数据传递给 C++ 时,您不小心告诉它(错误地)将 nul 终止符包含到字符串中。

我确信编码并不意味着包含 nul 终止符,因为协议规范给出了字符串“testing”(作为字段 2)的示例,它编码为:

12 07 74 65 73 74 69 6e 67

the12是字段头(字段 2,以长度为前缀);the07是长度,接下来的 7 个字节 ( 74... 67) 是有效负载,采用 UTF-8 编码。注意:没有 nul 终止符。

于 2013-05-08T12:27:51.303 回答