赞
踩
事情是这样的,朋友有个软件,但它是单机版本
,他想实时向服务器传输生成出来的报告,算是服务器那边有个备份。
我先看了一下,软件是C/C++的,CRT也是版本齐全,而且那台电脑也不允许装什么其他环境了,我很自然的就用C/C++写了,而服务端使用JAVA写的,因为服务器那边本来就装了JAVA环境,但没有10以上版本的CRT,所以我就用了2个不同语言写了。
网络字节顺序规范
是大端
方式存储,这就指定了发送方
和接收方
必须是大端
方式发送
和接收
,但是我们通常在C/C++中并不完全遵守这个规范,很常见,我们只将必要的信息进行大端转换,因为这些信息是由系统处理的,应用层的SOCKET库
并不需要我们去校验
TCP头和IP头,所以我们通常只使用htons
转换端口和inet_pton
或inet_addr
转换IP地址,但我们从来不转换消息体的存储方式,因为接收时buffer
同样是按顺序
的。
如果两边同时使用c/c++
写,那么不会出现这个问题,因为我们知道存储int
的时候是小端存储
,低位
在低地址
,高位
在高地址
,客户端通过socket
传输int
的时候其实就是从int
的首字节地址
开始传输4个字节
,如果同时使用c/c++
,接收
的时候同样是从首字节地址开始
,所以不会造成乱序问题。
比如:
20 = 0x14
由于是占4个字节
,高位补0x00
,其最终为0x00000014
。
存储在内存中的格式就是14 00 00 00
。
但java
服务端接收后,如果直接用ByteBuffer
的getInt
方法,这个数实际上就是错的,因为ByteBuffer
的getInt
方法默认是大端
方式转换,它完全遵循网络字节顺序
,这也许是因为Java
中的char
固定为2字节
。
byteBuffer.order(ByteOrder.LITTLE_ENDIAN) ;
byteBuffer.getInt();
或者我们手动转换,我们通过read(bytes,0,4)
,读取4个byte
,然后手动将其低位存储到低地址
,高位存储到高地址
,那么这个int
就是对的了。
private static int bytes2Int(byte[] byteVal) {
if (byteVal == null || byteVal.length != 4) return 0;
/*
&0xff 的原因是将它原内容转为int再做位移和或运算
强转int由于java没有unsigned,所以byte是带符号位的
当单byte>128的时候强转int会出现负数(符号扩展)
最好的办法就是&0xff
*/
return byteVal[0] & 0xff | ((byteVal[1] & 0xff) << 8) | ((byteVal[2] & 0xff) << 16) | ((byteVal[3] & 0xff) << 24);
}
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。