[版权声明] 本站内容采用 知识共享署名-非商业性使用-相同方式共享 3.0 中国大陆 (CC BY-NC-SA 3.0 CN) 进行许可。
部分内容和资源来自网络,纯学习研究使用。如有侵犯您的权益,请及时联系我,我将尽快处理。
如转载请注明来自: Broly的博客,本文链接: Java与C++的socket通信问题
最近在由于某种原因,来了兴趣,准备做个项目,用Spring Boot + Netty写个简单的聊天服务器,其中有一个客户端用MFC来写。
这里就涉及到Java与C++的通信问题。
说这个之前,先来了解一下相关知识:字节序
详细介绍请看wiki的介绍《Endianness》(这个链接是英文的,中文的我这里打不开,不知道是不是被墙了)
字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
主要有 big-endian 和 little-endian 两种格式,
big-endian:内存地址从左到右与值由低到高的顺序相对应。
little-endian:地址低位存储值的低位 ,地址高位存储值的高位。
Java遵循的是 big-endian,而C++依赖于操作系统环境,大部分操作系统遵循的是 little-endian,Windows下的是 little-endian。
如果两者之间进行字节流通讯,比如socket传输,那么问题就来了!因为大家写内存的方式不同,单字节数据还没问题,但是多字节数据,就会导致乱码或者其他不正确的数据产生。
举个例子,一个十进制数字16909320,二进制表示即为 00000001 00000010 00000100 00001000
Java和C++的int类型占用4个字节,32bit,那么这个数字在内存显示的方式为
内存地址 | a | a+1 | a+2 | a+3 |
---|---|---|---|---|
Java(Big-endian) | 00000001 | 00000010 | 00000100 | 00001000 |
C++(Little-endian) | 00001000 | 00000100 | 00000010 | 00000001 |
如果Java上数字是正确的,不做任何改变传输到C++,然后会被解析成 00001000 00000100 00000010 00000001,即数字为134480385
所以两者直接通信,必须对这方面做处理,无论是在传输前转换还是传输后再解析都可以。
处理的方法很多,其中一种比较简单就是移位,即把字节序调整正确:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class EndianUtil { /** * convert big-endian to little-endian */ public static final short BE2LE16(short x) { return (short) ((x & 0xFF) << 8 | 0xFF & (x >> 8)); } /** * convert big-edian to little-edian */ public static final int BE2LE32(int x) { return (x & 0xFF) << 24 | (0xFF & x >> 8) << 16 | (0xFF & x >> 16) << 8 | (0xFF & x >> 24); } } |