c# 通信中的字节序处理。

最近在写一个短信发送功能。客户端使用c#和java短信网关进行网络通信。

我之前用java进行开发,一切正常。但是,我切换到c#,无法收到网关响应。

想了半天,才意识到是不是网络字节序问题,

Java默认是big-endian字节序,与网络字节序一致,所以不转换就不会有问题,

而c#在windows平台上是little endian。

网络发送的字节流是按照big-endian顺序发送的,即从左到右,与c#的little-endian顺序相反,导致网关无法正常识别协议。

尝试在c#中转换字节序,通信成功。

C#中有两种字节序转换方法。

对于非字符串,先使用System.BitConverter.GetBytes()方法读取字节数组,然后使用Array.Reverse()将字节数组反转,得到大端字节数组。

代码:

短 x = 6;

byte[] a=System.BitConverter.GetBytes(x); //获取小端字节顺序数组

Array.Reverse(a); //将数组反转为大端字节序。

另外,c#直接提供了网络字节序转换的方法。

System.Net.IPAddress.HostToNetworkOrder(本机到网络转换)

System.Net.IPAddress.NetworkToHostOrder(网络字节到本地)

推荐使用这个方法,简单有效。

代码示例:

短 x = 6;

short b = System.Net.IPAddress.HostToNetworkOrder(x); //将x转换为对应的big-endian字节数

byte[] bb = System.BitConverter.GetBytes(b);//直接得到的是大端字节数组。

对于字符串类型:使用System.Text.Encoding.Default.GetBytes();直接获取字符串对应的字节数组。

不知道为什么这个方法会直接获取一个big-endian字节数组。无需转换。

后来查了一下,发现是字符串的字节序问题。由于gbk和utf-8都使用单个字节来表示数字,因此不存在字节序问题,并且它们被用于许多不同的系统架构中。对于UTF-16来说,一个整数是用双字节来表示的,所以会存在字节序问题,并且分为大端和小端unicode。

System.Text.Encoding.Default.GetBytes();在我的简体中文系统上,是用gb2312编码的,是单个字,所以不存在字节序问题。

补充:“对于任何字符编码,编码单元的顺序是由编码方案指定的,与字节序无关。例如GBK的编码单元是字节,用两个字节来表示一个中文字符。两个字节的顺序是固定的,不受CPU字节顺序的影响。UTF-16的编码单位是字(双字节)。字之间的顺序是由编码方案指定的。只有里面的字节排列word会受到endian的影响。”,所以UTF-8不存在字节序问题。字节序问题是由于需要使用两个以上的字节来表示整数而产生的。 UTF-8只是字节流,不存在字节顺序问题。然而,将这些字节流转换为 Unicode 比其他传输方法更复杂。以字节为单位进行编码,无论一个汉字有多少字节,都不存在字节序问题。
请注意,字节顺序问题并不是指多个字节传输的顺序。这是固定的,无可争议的。它指的是多字节编码在机器中的表示方式。
char str[] = "abaksdkakskasklasflk";这不存在字节顺序问题。
但是
int str[] = {0x11223344, 2, 3} 存在字节顺序问题。因为str[0]的相同值在不同的机器上表示不同。

其余的是字符编码中的字节顺序。例如UTF-16使用两个字节来表示一个字符,但是系统并不知道这两个字节内部是如何排序的,所以必须指定字节顺序。然而在UTF-8中,由于几个字节的表示方式不同,所以必须从表示长度的字节开始读取,相当于知道从队列的开头和结尾从哪里开始读取,所以不存在字节顺序问题。

附字节顺序说明:

为什么要关注字节顺序问题?你可能会问。当然,如果你写的程序只运行在单机环境中,不与其他人的程序交互,那么你完全可以忽略字节序的存在。但是如果您的程序想要与其他人的程序交互怎么办?尤其是当你把微型计算机上的计算结果应用到计算机集群上时。这里我想谈谈两种语言。 C/C++语言编写的程序中数据存储的顺序与编译平台所在的CPU有关,而JAVA编写的程序只采用big endian方式存储数据。试想一下,如果你在x86平台上用C/C++语言编写的程序与别人的JAVA程序通信会发生什么?以上面的0x12345678为例。你的程序向别人传递一个数据,将0x12345678的指针传递给JAVA程序。由于JAVA使用big endian来存储数据,它自然会将你的数据翻译为0x78563412。 。什么?变成了另一个数字?是的,这就是结果。因此,在将C程序传递给JAVA程序之前,有必要进行字节顺序转换。

 用文字解释可能太抽象了,下面我用图片来解释。例如数字0x12345678在两个不同endian的CPU中的存储顺序如下:

  大端

  低地址 高地址

  ----------------------------------------------------->

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  | 12 | 12 34 | 34 56 | 56 78 |

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  小端

  低地址 高地址

  ----------------------------------------------------->

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  | 78 | 78 56 | 56 34 | 34 12 |

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+