传递给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

解决方法

假设您需要通过电线传递一个短\ int \长号。通过线路,您只能传递二进制数据,并且该数字需要超过1个字节来表示。然后是一个问题-一个人可以从左到右或从右到左读取多个字节,结果会有所不同。这意味着协议应该指定此名称,或者如果未指定,则应该有一个约定。这样的约定存在于网络协议中,除非另有说明,否则将使用big endian。

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

request.Write(length)

在小字节序体系结构上,然后在网络上写入两个字节01-00。但是,big endian中的01-00个字节表示完全不同的数字-256。如果在连接线另一端的使用者使用了大字节序,则它将读取两个字节,并将它们解释为完全不同的消息长度。 / p>

为避免这种情况-如有必要,您可以将上述数字转换为大端数字:

request.Write(IPAddress.HostToNetworkOrder(length))

如果您使用的是小端HostToNetworkOrder会将短1转换为256,然后在这种情况下也使用小端的BinaryWriter将写入字节00-01(小端256的表示形式) 。如果您使用大字节序,则HostToNetworkOrder将返回1,而BinaryWriter将再次在网络上写入相同的00-01字节,以确保表示一致。

要跟进您的更新:

有问题的代码在UTF-8中写字符串“ API”(3个字节),然后写一些EOL字节(现在有4个字节),然后通过写零整数来保留4个字节。它继续写另一个东西,然后返回到这个保留的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);