我必须将短信作为无符号短信发送给TCPServer。
问题是Java不支持usigned短路: 我尝试过:
byte[] data = new byte[3];
short port = 5025;
data[0] = 1;
data[1] = (byte)(port & 0xff);
data[2] = (byte)((port >> 8) & 0xff);
这就是我在C ++中将数据转换为无符号短语的方式
// Bytes to Short (uint16)
unsigned short port = (data[1] << 8) | data[2];
那么如何在Java中解决这个问题呢? (我不想改变C ++代码中的东西)
编辑:// 我的新Java代码:
byte[] data = new byte[3];
short port = 1151; // short or int doesn't matter in this case
ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put((byte) 1);
buffer.putShort(port);
out.write(buffer.array());
C ++代码:(相同)
unsigned short port = (data[1] << 8) | data[2];
如果端口在0-1151和16384-32767之间,我得到了正确的端口,但是为什么它不适用于其余端口?
答案 0 :(得分:3)
没关系。只需将其放入short
即可。签署short
无关紧要; short
仍然是16位。
重要的是这里的字节顺序。如果你通过网络发送,那就是它的大端。
ByteBuffer
的默认值,以及Java的所有数字基元类型的默认值。
那么,你做什么的?对于您的特定示例,请:
// Just for a short...
final ByteBuffer buf = ByteBuffer.allocate(3);
buf.put((byte) 1);
buf.putShort(myShort);
final byte[] contents = buf.array();
// send the byte[]
现在,如果.put*()
中有更多ByteBuffer
,请分配必要的空间等。
但是。你说你不想改变你的C ++代码...这在架构之间是不可移植的。如果您希望在C ++中通过网络读取/写入16位值,请使用ntohs()/htons()
。
(也许有比这更好的API;我已经很长时间没有在C / C ++中进行过高级网络编程了)
答案 1 :(得分:0)
我的观点略有不同。 OP正确地使用位移进入小端,因此除非他处理非常规字节的字节,否则C ++的可移植性将会很好。通信协议违背了网络惯例的大端,但有时支持遗留系统就是这样。
如果端口变量的用户不在提供的代码之外,请使用int并仅像上面的Java示例中那样发送所需的位。如果你正在经过这个港口,那就很难不得不扭曲这些该死的标志位,迟早你会搞砸它。如果没有其他人需要玩端口,那么签名并不重要。
byte[] data = new byte[3];
int port = 5025; // short or int doesn't matter in this case
data[0] = 1;
data[1] = (byte)(port & 0xff);
data[2] = (byte)((port >> 8) & 0xff);
当回读并获得65440时,看起来你使用了一个字符,你的字节在移位时得到了扩展符号。这里有一些测试代码,所以你可以玩,看看发生了什么。
#include <cstdio>
int main()
{
unsigned short val = 32896;
char hi = (char)((val >> 8) & 0xFF);
char lo = (char)(val &0xFF);
printf("Watch what the sign bit can do to the bytes here:\n");
printf("Value: %d, raw in hex: %04x, Hi byte: %02x, Low byte: %02x\n", val, val, hi, lo);
printf("This one only works if the low byte doesn't sign extend\n");
char datas[3] = {0, hi, lo};
unsigned short port = (datas[1] << 8) | datas[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
printf("This one works, but will not for an integer\n");
port = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled short: %u, in Hex: %04x\n", port, port);
unsigned int bigport = (datas[1] << 8) | (datas[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
printf("With unsigned characters it just works\n");
unsigned char datau[3] = {0, hi, lo};
port = (datau[1] << 8) | datau[2];
printf("Reassembled short: %u, In Hex: %04x\n", port, port);
bigport = (datau[1] << 8) | (datau[2] & 0xFF);
printf("Reassembled int: %u, in Hex: %04x\n", bigport, bigport);
}
输出:
Watch what the sign bit can do to the bytes here:
Value: 32896, raw in hex: 8080, Hi byte: ffffff80, Low byte: ffffff80
This one only works if the low byte doesn't sign extend
Reassembled short: 65408, In Hex: ff80
This one works, but will not for an integer
Reassembled short: 32896, in Hex: 8080
Reassembled int: 4294934656, in Hex: ffff8080
This one just works
Reassembled short: 32896, In Hex: 8080
Reassembled int: 32896, in Hex: 8080
那发生了什么?
(datas[1] << 8) | datas[2]
这两个数字必须按比例缩放为短并且它们是有符号的,因此0x80变为0xFF80。实际上,它们变成了整数,但那是另一个故事。
(0xFF80 << 8) | 0xFF80
简化为
0x8000 | 0xFF80
那个OR到
0xFF80
AKA 65408,而非32896。
在这种情况下,unsigned char是你的朋友。 Java可能存在问题,但C ++肯定会被破坏。