为了理解网络socket解析请求消息头部的过程,今天把c#和java的内存结构学习了一下,主要是读取二进制数据的区别,这是个非常值得注意的问题,如果你不使用string自带的解析接口的话。
现在假设请求对象维护了如下的结构:
/// +-------+---+-------------------------------+
/// |request| l | |
/// | name | e | request body |
/// | (5) | n | |
/// | |(2)| |
/// +-------+---+-------------------------------+
/// request name: the name of the request, 4 chars, used for matching the processing command
/// len: the lenght of request data, two bytes, 0x00 0x02 = 2, 0x01 0x01 = 257
/// request data: the body of the request
请求的key占了5个字节,如果要获取请求体的长度,应该从第6个字节开始读。问题来了,已知这个请求对象在接收包的位置偏移是offset(字节),怎么从内存中读取len这个值?
首先,我们来看一个例子,如果一个16进制的值在内存中怎么存:
你使用c#是小端序的,也就是说低位对低地址,俗称小对小
0X02|0X02|
0X01|0X01|
以上是小端序的内存结构
值读出来就是2*2^8+1*2^0,0X02 0X01
在java 是大端序,也就是说高位对低地址,俗称大对小
0X02|0X01|
0X01|0X02|
以上是大端序的内存结构
值读出来就是1*2^8+2*2^0,0X01 0X02,如果从网络上获取数据解析成二进制数组的时候就要注意高位和低位的顺序,不然就会出现如上的差(错)别(误)。
所以对于写c#的童鞋,GetBodyLengthFromHeader()函数应该这样写
protected override int GetBodyLengthFromHeader(byte[] header, int offset, int length)
{//!!!!!!!!!!!!!!C#小端序!!!!!!!!!!!!!!!
// int dataLen = header.ToInt(offset + 4);
int dataLen = (int)header[offset + 5] * 256 + (int)header[offset + 6];
//Console.WriteLine("data length:" + dataLen.ToString());
return dataLen;
}
如果想要自动将端序改为网络公用的(大端序),可以用函数HostToNetworkOrder获取
int bigend_a=IPAddress.HostToNetworkOrder(lowend_a)
接下来就不用你去关心c#接收网络数据或者java处理后的数据高低位转换问题了。