内容简介:由于我代码使用基于 JVM 的语言写的,所以所有数字类型都是带符号的,也就是 signed 类型。但是 TLS 层的数据都是 unsigned 类型的数字,这就导致数据从 Socket 流走到 JVM 层之后会由于 JVM 的语言没有 unsigned 类型出现数字越界的问题。比如一个 u_char, 值是 128,由于它大于了 127,走到 Java 这边之后,byte 的范围是 -128~127,就会被解析为 -128 。(128=11111111, bit位的首位在 signed 类型时表示符号位,首
由于我代码使用基于 JVM 的语言写的,所以所有数字类型都是带符号的,也就是 signed 类型。但是 TLS 层的数据都是 unsigned 类型的数字,这就导致数据从 Socket 流走到 JVM 层之后会由于 JVM 的语言没有 unsigned 类型出现数字越界的问题。
比如一个 u_char, 值是 128,由于它大于了 127,走到 Java 这边之后,byte 的范围是 -128~127,就会被解析为 -128 。(128=11111111, bit位的首位在 signed 类型时表示符号位,首位为 1 表示这是一个负数,负数在 JVM 中又是以补码形式存储,所以 11111111 转化为原码之后就是 10000000 => 128,加上负数就变成 -128 了)。
由于上面的越界问题,所以从 Socket 中读数据都读出来存为 int,写数据时再转化为 u_char 写入。写入的过程就涉及字节序问题。
就比如发送每条 TLS 消息时,你都需要在消息体外面包裹一层 TLSPlaintText 结构,这个结构中必须写入一个 16 位的数字(length) 去表示数据的大小。16 位的就包含了2个字节,在这2个字节的写入上,我就遇到了问题。
我们知道 OutputStream 提供的 write
接口接收的数据单位是以字节为单位的,现在我想写入2个字节,这2个字节的写入顺序就要受字节序的影响了。
开始我是这样写的:
fun ByteBuffer.putU16(value: Int) = run { put((value and 0xFF).toByte()) put((value shl 8).toByte()) }
因为我们写入时是以32位 int 写的,所以先取低8位写入第一个字节,再把32位数左移8位,剩下的写入第二个字节。这样就把32位数中的16位写入了2个字节中。
当我天真的以为这样就成功时,运行发现 Server 反馈我发送的数据有问题,通过 Wireshark 我发现,wireshark 解析出来的 length 尽然和我写入的length 值不相同。
原因是上面的写入顺序是 litte-endian 的,而网络协议一般都是按照 big-endian 的。
所以需要修改代码为:
fun ByteBuffer.putU16(value: Int) = run { put((value shr 8).toByte()) put((value and 0xFF).toByte()) }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Pro HTML5 and CSS3 Design Patterns
Michael Bowers / Apress / 2011-11-15 / GBP 35.50
Pro HTML5 and CSS3 Design Patterns is a reference book and a cookbook on how to style web pages using CSS3 and HTML5. It contains 350 ready--to--use patterns (CSS3 and HTML5 code snippets) that you ca......一起来看看 《Pro HTML5 and CSS3 Design Patterns》 这本书的介绍吧!