Java提供了对任意字符集的支持,而且每种实现都必须支持以下至少一种字符集: US-ASCII (ASCII 的另一个名字), ISO-8859-1, UTF-8, UTF-16BE,UTF-16LE,UTF-16。
调用 String 实例的 getBytes()方法,将返回一个字节数组,该数组根据平台默认字符集(default charset)对 String 实例进行了编码,所以发送者和接收者必须在文本字符串的表示方式上达成共识。
位操作:布尔值编码
位图(Bitmaps)是对布尔信息进行编码的一种非常紧凑的方式,通常用在协议中。位图的主要思想是整型数据中的每一位都能够对一个布尔值编码--通常是 0 表示 false,1 表示true。
掩码(mask)是一个的整数值,其中有一位或多位被设为 1,其他各位被清空(即,设为 0)。
将 int 中的各位从 0到 31 进行编号,其中 0代表最低位。一般来说,如果一个 int值在第 i 位值为 1,其他位都为 0 的话,该 int 型整数的值就是 2 i次方。因此编号为 5 的位表示
32,编号为12 的位表示4096,等等。
要设置 int 变量中的特定一位,需要将该 int 值与特定位对应的掩码进行按位或操作(|)。
bitmap |= BIT5;
要清空特定一位,则将该整数与特定所对应的掩码的按位补码(特定位为 0,其他位为 1),进行按位与(bitwise-AND)操作。Java 中的按位与操作符是&,而按位补码操作符是~:
bitmap &= ~BIT7;
通过将相应的所有掩码进行按位或操作,一次设置和清空多位:
bitmap &= ~(BITS2AND3|BIT5);
要测试一个整数的特定位是否已经被设置,可以将该整数与特定位对应的掩码进行按位与,并将操作结果与 0 比较。
boolean bit6Set = (bitmap & (1<<6)) != 0;
成帧与解析
应用程序协议通常处理的是由一组字段组成的离散的信息。成帧(Framing)技术则解决了接收端如何定位消息的首尾位置的问题。无论信息是编码成了文本、多字节二进制数、或是两者的结合,应用程序协议必须指定消息的接收者如何确定何时消息已完整接收。
如果通过 TCP套接字来发送消息,情况将变得更复杂,因为 TCP协议中没有消息边界的概念。如果一个消息中的所有字段都有固定的长度,同时每个消息又是由固定数量的字段组成的话,消息的长度就能够确定,接收者就可以简单地将消息长度对应的字节数读到一个 byte[]缓存区中。
如果接收者试图从套接字中读取比消息本身更多的字节,将可能发生以下两种情况之一:如果信道中没有其他消息,接收者将阻塞等待,同时无法处理接收到的消息;如果发送者也在等待接收端的响应信息,则会形成死锁(deadlock)。另一方面,如果信道中还有其他消息,则接收者会将后面消息的一部分甚至全部读到第一条消息中去,这将产生一些协议错误。因此,在使用 TCP套接字时,成帧就是一个非常重要的考虑因素。
最简单并使代码最简洁的方法是将这两个问题分开处理:首先定位消息的结束位置,然后将消息作为一个整体进行解析。
基于定界符:消息的结束由一个唯一的标记(unique marker,)指出即发送者在传输完数据后显式添加的一个特殊字节序列。这个特殊标记不能在传输的数据中出现。
显式长度:在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。
基于定界符的方法的一个特殊情况是,可以用在 TCP连接上传输的最后一个消息上,在发送完这个消息后,发送者就简单地关闭(使用 shutdownOutput()或 close()方法)发送端的 TCP连接。接收者读取完这条消息的最后一个字节后,将接收到一个流结束标记(即 read()方法返回-1),该标记指示出已经读取到达了消息的末尾。