Java 和 C/C++ 之间通信的真正问题是字节顺序问题。如果您要发送二进制数据,您必须清楚完整地设计通信结构,包括数字大小(以字节为单位)、位顺序(lsb/msb、交换字节或短的非交换字节、整数和longs)和结构打包(结构中字段之间的填充字节数)。
如果可以避免,我建议您不要使用二进制通信。有两个原因;
- 无需担心位顺序、字节交换和结构打包。
- 窃听通信而不解码数据。您仍然有 ascii/unicode 问题。
编辑
在 C/C++ 中,数据的存储方式使 CPU 访问变得快速而轻松。类/结构的字段在字边界上对齐(因为大多数 CPU 只能以完整的字块访问内存),并且位被排序以匹配 CPU。但是,CPU 可以有不同的位顺序和字长(16、32、64,...)。大多数英特尔 CPU 都是小端,而大多数其他设计都是大端。为了让生活更有趣,java 虚拟机在每个平台上都是大端的。 http://en.wikipedia.org/wiki/Endianness
因此,如果您希望两台 C/C++ 机器能够通信,那么您必须以双方都能读取的方式发送数据。通常,要在异构环境中进行通信(称为“有线”),您需要指定所有通信都以特定格式完成。 TCP/IP 使用 MSB(最高有效位)排序。然后所有程序都必须从有线格式转换(如果需要)。
因为 CPU 以字长块的形式消耗内存,所以编译器会将填充字节放在不填充整个机器字的字段之间。对于读取 32 位字的机器,结构如下:
struct example1 {
char someFlag;
int someCount;
};
实际上会占用 8 个字节的内存。第一个字段由一个数据字节和 3 个填充字节组成,因此整数引用在字边界上对齐。如果一个天真的通信器试图以这种结构发送数据,比如send(&example1, sizeof(example1)); 到另一个具有不同字长或字节顺序的系统,而另一个系统发送read(&example1, sizeof(example1));,那么 example1.someCount 的值可能与预计。
在您将 Java 投入其中之前,大部分内容通常都是学术性的。因为Java总是MSB格式。因此,从 C/C++ 应用程序发送到 Java 应用程序,即使在相同的硬件上,也可能导致同样的意外结果。
Java 包含我最喜欢的 I/O 类 java.nio.ByteBuffer。它能够从几乎任何来源读取整数、长整数、浮点数和双精度数。如果您知道数据是如何创建的,它将读取它。 ByteBuffer有getShort、getInt等方法可以获取任意类型,还有order()方法可以设置数据的字节顺序。