【问题标题】:Putting a short into 2 bytes of string将short放入2个字节的字符串中
【发布时间】:2011-12-17 00:41:39
【问题描述】:

所以我正在为在线游戏制作自己的网络协议,为了节省空间,每条消息(通过 TCP 发送)都有一个很短的 ID,2 个字节,所有从服务器发送到客户端的消息,反之亦然反之亦然是字符串,如何在 java 中仅用 2 个字节(字符)将 short 转换为字符串?

更新:我可能不清楚我想要什么... 我希望能够将一个 short int 转换为 2 个字符,这样我就可以通过网络以 2 个字节的字符串格式发送 short 并将其解码回另一端的 short(在 actionscript 3 中)。

一个字符可以容纳 256 个可能的值,对吧?所以 256*256=65,536 是 unsigned short int 的大小!

这是我目前得到的:

public static String toCode(int c){

    if(c <= 255 ){
        return Character.toString((char)c);
    }else{
        return null;
    }
}

public static int fromCode(String c){
    return ((int)c.charAt(0));//Return the character code of the send string, 1 char only
}

这可以将一个 int 变成一个可以通过网络发送的单个字符,现在我只需要让它使用 2 个字符,它最多可以做一个短。

【问题讨论】:

  • 你不能——这就是为什么首先有short...
  • 如果您想节省空间,我认为您不应该使用字符串 :)
  • Java char 是 16 位,而不是 8...
  • 看看这个问题stackoverflow.com/questions/231051/…。 Java 中的字符串只有 2 个字节是不可能的。

标签: java string actionscript-3 byte short


【解决方案1】:

这对于某些“可能”的值是可能的。

String s = "" + (char)myShort;

然而,结果字符串可能无效,因为并非所有 16 位整数都表示有效(UTF-16 编码)代码点!也就是说,结果字符串可能是 invalid UTF-16 序列。由于违反了基本规则,各种字符串函数和/或编码/解码可能会导致“奇怪的行为”(我认为可能发生的事情有些松懈,但...)。您已被警告 - 请参阅底部示例,仅显示一种可能的表现形式。

tl,博士。 请勿在此类网络传输中使用字符串*。相反,使用字节数组(或 ByteBuffers)并将 short 作为两个八位字节发送,高位和低位。 (哦,我有提到ByteBuffers吗?看看方法...)如果需要发送字符串,可以对其进行编码(UTF-8),也可以在数据包中作为“字节”发送。

当然,使用standard SerializationProtocol buffers 来处理数据包很可能更简单...肯定胜过自定义编码。 (另外,protocol buffers 做了一些巧妙的技巧,比如 zig-zag 整数编码......)

编码愉快:)


*尽管 Quake 3 使用字符串来表示许多网络消息……但是,它将值“编码为纯文本”——例如"xyz=1234" -- 并使用了一堆猴子手序列化代码。


查看输出中的最后一个值,了解为什么这个“字符串填充”可能是坏东西;-)

public class test1 {
    public static void main (String[] args) throws Exception {
        int s1 = 0xd801;
        short s = (short)s1;
        String x = "" + (char)s;
        System.out.println("orig int: " + s1);
        System.out.println("orig short: " + s);
        System.out.println("length of string: " + x.length());
        System.out.println("value in string: " + (short)x.codePointAt(0));
        int s2 = ((short)x.codePointAt(0)) & 0xffff;
        System.out.println("restored value: " + s2);
        byte[] xb = x.getBytes("UTF8");
        System.out.println("encoded size: " + xb.length);
        String x2 = new String(xb, "UTF8");
        System.out.println("decode:" + x2);
        System.out.println("decode length:" + x2.length());
        int s3 = ((short)x2.codePointAt(0)) & 0xffff;
        System.out.println("value in string:" + s3);
    }
}

JDK 7、Windows 64 中的结果。

orig int: 55297
orig short: -10239
length of string: 1
value in string: -10239
restored value: 55297
encoded size: 1
decode:?
decode length:1
value in string:63    WHAT IS THIS?!?!?! NOOOOO!!!!!

【讨论】:

  • 哦,请解释一下-1。
  • 我不能使用标准序列化,因为客户端将在闪存中,服务器在 java 中,所以我需要一些自定义序列化。
  • @Bubby4j 在任何情况下,将序列化和传输的数据视为八位字节序列,而不是字符串(至少来自 Java)。我不确定 Flash 对字节流有什么支持或它如何处理字符串/字符串解码。仅使用“胖”的基于文本的消息格式(甚至是 JSON)可能是有益的,这将是“字符串安全的”,除非已证明需要将其编码为非常紧凑的内容。其他选项包括二进制数据的基本编码(base64 很常见,但自定义 base96/128 仍然是 UTF-8 友好的;它不必是“可读”编码,只需“有效”编码)。跨度>
  • @Bubby4j “UTF-8 友好”字符串是指所有(或几乎所有)字符都可以编码为单个八位字节的字符串;所有常规 ASCII 字符都被编码为一个八位字节。
【解决方案2】:

DataOutputStream.writeShort/DataInputStream.readShort?

【讨论】:

  • +1 很好的一点——序列化流有相对简单的方法。
【解决方案3】:

我不使用 java,但我认为您只想使用强制转换运算符。如果您的简称为 mynumber,请使用 (char) mynumber。也就是说,如果您打算在这些位从另一侧出来时将它们视为短路。祝跨平台好运,但如果您使用“short”作为字段的定义而不是“16 位带符号的 int”,则存在一些深奥的平台。

【讨论】:

    猜你喜欢
    • 2011-08-10
    • 2021-10-08
    • 1970-01-01
    • 2021-10-15
    • 1970-01-01
    • 2021-12-19
    • 2010-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多