问题描述
我正在查看别人写的一些代码,如下所示:
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);