传递给 IPAddress.HostToNetworkOrder 的参数的目的是什么?

What is the purpose of the parameter passed to: IPAddress.HostToNetworkOrder?

我正在看别人写的一些代码,看起来像这样:

protected override void CloseAndSend(BinaryWriter request, uint lengthPos)
{
request.Seek((int)lengthPos, SeekOrigin.Begin);
request.Write(IPAddress.HostToNetworkOrder((int)(request.BaseStream.Length - lengthPos - sizeof(int))));

//more code here.
}

我知道 IPAddress.HostToNetworkOrder 确保使用适当的字节顺序,但是争论的目的是什么,即 (int)(request.BaseStream.Length - lengthPos - sizeof(int)))?我读过这个:https://docs.microsoft.com/en-us/dotnet/api/system.net.ipaddress.hosttonetworkorder?view=netcore-3.1。我找不到任何例子,因此找不到问题的原因。我用谷歌搜索了两个小时。

更新

这是填充 BinaryWriter 的代码(按正确顺序):

    byte EOL = 0;
        BinaryWriter writer = new BinaryWriter(new MemoryStream());
        writer.Write(UTF8Encoding.UTF8.GetBytes("API"));
        writer.Write(EOL);
        writer.Write((int)0);
        writer.Write(UTF8Encoding.ASCII.GetBytes("v100..155"));
        //request.BaseStream.Length - lengthPos - sizeof(int)=9
        //writer.BaseStream.Length=17

假设您需要通过网络传递一个 short\int\long 号码。在网络上你只能传递二进制数据,而这样的数字需要超过 1 个字节来表示。那么就有一个问题——一个人可以从左到右或从右到左读取多个字节,结果会不同。这意味着协议应该指定这一点,或者如果未指定 - 应该有一个约定。网络协议存在这样的约定,如果没有另外说明,则使用大端。

现在,BinaryWriter 始终使用当前体系结构的字节序(例如,您可以通过 BitConverter.IsLittleEndian 检查)。如果您当前的体系结构是小端字节序并且您需要通过网络写入一个数字(例如遵循 TCP 协议中常见的消息长度)怎么办?假设长度为 1,为此长度保留的字节数为 2(因此,总长度为 short)。如果你只是做

request.Write(length)

在小端架构上,然后通过网络写入两个字节 01 - 00。但是,big endian 中的 01 - 00 字节代表完全不同的数字 - 256。线路另一端的消费者,如果他假设 big endian 应该如此 - 将读取两个字节,并将它们解释为完全不同的消息长度。

所以为了避免这种情况 - 如有必要,您将所说的数字转换为大端:

request.Write(IPAddress.HostToNetworkOrder(length))

如果你在小端 HostToNetworkOrder 会将短 1 转换为 256,然后 BinaryWriter 在这种情况下也使用小端将写入字节 00 - 01(256 在小端的表示端)。如果你在大端,那么 HostToNetworkOrder 将 return 1 返回,并且 BinaryWriter 将再次通过网络写入相同的 00 - 01 字节,确保一致的表示。

跟进您的更新:

有问题的代码以 UTF-8(3 个字节)写入字符串“API”,然后是一些 EOL 字节(现在我们有 4 个字节),然后通过写入零整数保留 4 个字节。它继续写另一个东西,然后 returns 回到这个保留的 4 字节整数(包含所有零字节)的位置。然后计算该 4 字节整数(“v100..155”等)之后的内容的长度,并将该长度写入保留位置。它以一种非常奇怪的方式只写入以下数据的长度,这在大多数 TCP 协议中很常见。

如果这就是全部代码,那么简单的方法就是:

    byte EOL = 0;
    BinaryWriter writer = new BinaryWriter(new MemoryStream());
    writer.Write(UTF8Encoding.UTF8.GetBytes("API"));
    writer.Write(EOL);
    var data = UTF8Encoding.ASCII.GetBytes("v100..155");
    writer.Write(IPAddress.HostToNetworkOrder(data.Length));
    writer.Write(data);