内容简介:由于我代码使用基于 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()) }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web 2.0 Architectures
Duane Nickull、Dion Hinchcliffe、James Governor / O'Reilly / 2009 / USD 34.99
The "Web 2.0" phenomena has become more pervasive than ever before. It is impacting the very fabric of our society and presents opportunities for those with knowledge. The individuals who understand t......一起来看看 《Web 2.0 Architectures》 这本书的介绍吧!