SQL server jdbc之prelogin数据包
2016-07-08 00:00
267 查看
为了做sql server的监控功能,需要了解SQL SERVER jdbc与SQL SERVER之间的通信协议。目前在Windows上面安装了sqlserver2016的developer版本。并且通过jdbc来操作数据库,可以得到jdbc的日志情况。通过日志可以了解到通信的过程,从通信的过程可以看到jdbc先发送了一个prelogin数据包到服务端。下面通过反编译的jdbc代码来学习prelogin包的内容。
prelogin数据包是在SQLServerConnection.class文件的Prelogin函数中进行构建的。与prelogin数据包相关的内容如下所示:
上面去掉了无关代码后,其中arrayOfByte1数组中的内容为prelogin数据包的初始内容。再在初始内容的基础上面通过初步计算得到结果需要发送的数据包内容,修改的数据过程如下所示:
1. 把clientConnectionId的内容复制到arrayOfByte1数组中
2. 把localActivityId的id内容复制到arrayOfByte1数组中
3.把localActivityId的Sequence写到arrayOfByte1数组中,Sequence的长度为4个字节。
通过上面的修改后,把arrayOfByte1中的内容通过tdsChannel的write函数发送出去。
现在需要弄清楚的是requestedEncryptionLevel,clientConnectionId,localActivityId.id, localActivityId.Sequence值得来源或者计算过程。
str2的值为encrypt,str3的值是根据参数进行取值,默认情况下是false。于是可以得到当连接参数中没有设置encrypt时,requestedEncryptionLevel的值为0.否则为1.
2. clientConnectionId
这个参数的赋值是在SQLServerConnection.java文件的connectHelper函数中,具体代码如下所示:
clientConnectionId是通过UUID.randomUUID函数包装的。我机器上面jdbc打印出来的ID为ClientConnectionId: c4000772-d238-4feb-a388-fa63320b03e7。
id是在ActivityId的构造函数中进行初始化的。
Sequence的长度是long型,所以长度不能超过4字节(FFFFFFFF)。
故通过上面的计算后能够得到prelogin的最终数据包格式是:
这个数据包的内容是来做jdbc的连接日志,是最终的结果。
prelogin数据包是在SQLServerConnection.class文件的Prelogin函数中进行构建的。与prelogin数据包相关的内容如下所示:
[code=language-java]byte[] arrayOfByte1 = { 18, 1, 0, 67, 0, 0, 0, 0, 0, 0, 16, 0, 6, 1, 0, 22, 0, 1, 5, 0, 23, 0, 36, -1, 0, 0, 0, 0, 0, 0, this.requestedEncryptionLevel, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ...... ActivityId localActivityId = ActivityCorrelator.getNext(); byte[] arrayOfByte3 = Util.asGuidByteArray(localActivityId.getId()); byte[] arrayOfByte4 = Util.asGuidByteArray(this.clientConnectionId); int i = arrayOfByte1.length - 36; System.arraycopy(arrayOfByte4, 0, arrayOfByte1, i, arrayOfByte4.length); i += arrayOfByte4.length; System.arraycopy(arrayOfByte3, 0, arrayOfByte1, i, arrayOfByte3.length); i += arrayOfByte3.length; long l = localActivityId.getSequence(); Util.writeInt((int)l, arrayOfByte1, i); i += 4; ...... try { this.tdsChannel.write(arrayOfByte1, 0, arrayOfByte1.length); this.tdsChannel.flush(); } ......
上面去掉了无关代码后,其中arrayOfByte1数组中的内容为prelogin数据包的初始内容。再在初始内容的基础上面通过初步计算得到结果需要发送的数据包内容,修改的数据过程如下所示:
1. 把clientConnectionId的内容复制到arrayOfByte1数组中
2. 把localActivityId的id内容复制到arrayOfByte1数组中
3.把localActivityId的Sequence写到arrayOfByte1数组中,Sequence的长度为4个字节。
通过上面的修改后,把arrayOfByte1中的内容通过tdsChannel的write函数发送出去。
现在需要弄清楚的是requestedEncryptionLevel,clientConnectionId,localActivityId.id, localActivityId.Sequence值得来源或者计算过程。
1. requestedEncryptionLevel
这个参数的赋值是在SQLServerConnection.java文件的connect函数中,具体代码如下所示:[code=language-java]str2 = SQLServerDriverBooleanProperty.ENCRYPT.toString(); str3 = this.activeConnectionProperties.getProperty(str2); if (str3 == null) { str3 = Boolean.toString(SQLServerDriverBooleanProperty.ENCRYPT.getDefa this.activeConnectionProperties.setProperty(str2, str3); } this.requestedEncryptionLevel = (booleanPropertyOn(str2, str3) ? 1 : 0);
str2的值为encrypt,str3的值是根据参数进行取值,默认情况下是false。于是可以得到当连接参数中没有设置encrypt时,requestedEncryptionLevel的值为0.否则为1.
2. clientConnectionId
这个参数的赋值是在SQLServerConnection.java文件的connectHelper函数中,具体代码如下所示:
[code=language-java]this.clientConnectionId = UUID.randomUUID(); assert (null != this.clientConnectionId);
clientConnectionId是通过UUID.randomUUID函数包装的。我机器上面jdbc打印出来的ID为ClientConnectionId: c4000772-d238-4feb-a388-fa63320b03e7。
3. localActivityId.id
从ActivityId.java文件中可以看到id也是一个UUID。取值的方法也是通过调用UUID.randomUUID函数来获得。具体的代码如下所示:[code=language-java]ActivityId() { this.Id = UUID.randomUUID(); this.Sequence = 0L; this.isSentToServer = false; }
id是在ActivityId的构造函数中进行初始化的。
4. localActivityId.Sequence
Sequence的值是通过+1来计算的。计算的函数如下所示:[code=language-java]void Increment() { if (this.Sequence < 4294967295L) { this.Sequence += 1L; } else { this.Sequence = 0L; } this.isSentToServer = false; }
Sequence的长度是long型,所以长度不能超过4字节(FFFFFFFF)。
故通过上面的计算后能够得到prelogin的最终数据包格式是:
[code=plain]12 01 00 43 00 00 00 00 00 00 10 00 06 01 00 16 ...C............ 00 01 05 00 17 00 24 FF 00 00 00 00 00 00 00 72 ......$........r 07 00 C4 38 D2 EB 4F A3 88 FA 63 32 0B 03 E7 C4 ...8..O...c2.... 7D 75 88 A5 79 E5 4F B2 D7 23 35 0E A9 2B DB 01 }u..y.O..#5..+.. 00 00 00
这个数据包的内容是来做jdbc的连接日志,是最终的结果。
相关文章推荐
- SQL Server 获取服务器时间的sql语句
- 使用UDEV SCSI规则在Oracle Linux上配置ASM
- sqlserver 2012 序列号
- SQL Server 创建约束图解(唯一 主键)
- mysql基础篇---mysql查询语句干货!!!
- Oracle TNS监听探讨
- PHP 使用 Redis
- Java 使用 Redis
- Redis 分区
- Redis 管道技术
- Python - 利用python编写的memcached启动脚本
- Redis 客户端连接
- Redis 性能测试
- Redis 安全
- Redis 数据备份与恢复
- Redis 服务器
- Redis 连接
- Redis 脚本
- Redis 事务
- Redis 发布订阅