在开发源工具解决Oracle中的问题时,必须了解TNS协议。在努力理解TNS协议的时候,Oracle JDBC驱动程序(classes12.zip)会是一个很有用的资源TNS头。
每个TNS包都有一个8字节的包头。包最前面的两个字节用来表示包的长度–不包括包头的大小。和所有的值一样,大小是大端字节的方式存储的。如果进行了校验,那么校验和会被存放在下一个字(WORD)内–默认情况下会对校验和进行校验,该字(WORD)的值为0x0000。下面的一个字节用来表示包的类型–例如,最常见的类型如下所示:
Connect packet Type 1
Accept packet Type 2
Ack packet Type 3
Refuse Packet Type 4
Redirect Packet Type 5
Data Packet Type 6
NULL Packet Type 7
Abort Packet Type 9
Resend Packet Type 11
Marker Packet Type 12
Attention Packet Type 13
Control Packet Type 14
要连接Oracle的时候,在TNS级,客户机向服务器发送一个链接包(类型1),这个包会指定客户将要访问的服务器名称。假定Listener知道这样的服务,那么接下来有两种可能:Listener可能会发送一个接收包(类型2)或者它可能用一个重定向包(类型5)将客户机指定向到另一个端口。
如果出现的是前一种情况,那么客户机将尝试进行身份验证。如果出现的是后一种情况,那么客户机会向自己被重定向的端口发送一个连接包并请求访问该服务。如果一切顺利的话,服务器会发出一个接收包并开始进行身份验证。所有的身份验证包都是类型为6的数据包。
如果Listener不知道客户机要求访问那个服务,那么它就会发送一个拒绝包–类型4。一旦通过身份验证,查询包和结果包都是数据包。偶尔您会看到类型为12(oxoC的包)–这是用来中断的标记包。例如,如果服务器希望客户机停止发送数据,那么它会向客户机发送一个标记包。
接下来继续介绍TNS包头的细节,下面的一个字节是包头标志位(header flag)。一般这些包头标志位是不使用的,不过在10g中客户机可能会将它的值设定为0x04。
最后的两个字节构成一个字(WORD),他用来存放头校验和–在默认情况下不使用这个字并将其设为0x000:
WORD 00 00 Pocket Size
WORD 00 00 Packet Checksum
Byte 00 Packet Type
Byte 00 Flags
Word 00 00 Header Checksum
在对包进行深入研究前,观察一下拒绝包(类型4)应该会有所帮助。拒绝包表示某种错误–例如,一个因“用户名/密码无效”而被拒绝登陆的错误–即ORA-01017。根绝这些错误,第54个字节指出了问题所在:A3代表无效的密码,a2表明没有这样的用户。很明显,即使从拒绝包中也可以得到可能有用的信息。
在线路上看到的包绝大多数是数据包(类型6)。对数据包而言,TNS包头后面的一个字(WORD)用来存储数据标志位(data flag)。如果这个包是一个断开连接包,那么这个字(WORD)被设为0x0040–否则,一般设为0x0000。
注意:所有的Oracle版本中都存在一个故障(bug):在服务器处理一个数据包(类型6)的时候,该数据包的数据标志位的第2个比特已被设置,但第1个(最不重要的)比特没有被设置(例如,数字2,6,10,14等)。如果服务器受到这样的包,它就会花费点所有可利用的CPU处理时间,以一个死循环而告终。很明显,这对服务器性能会产生消极的影响。
数据标志位后面的一个字节(第11个字节)决定了数据包里的内容:
0x01表示协议商议。这里,客户机将可以接受的协议版本发送给服务器–他们是6,5,4,3,2,1和0.服务器回复一个通用的版本(例如,6或5),不过它还会发送一些额外的信息,如它使用的字符集,这个集合共有多少个字符,版本字符串和服务器标志。
0x02表示交换数据类型表示法。
0x03表示一次双任务接口(Two-Task Interface,TTI)函数调用。下面的表列出了一些函数:
0x02 Open
0x03 Query
0x04 Execute
oxo5 Fetch
oxo8 Close
0x09 Disconnect/logoff
oxoc Autocommit on
oxod Autocommit off
oxoe commit
oxof rollback
ox14 Cancel
0x2B Describe
0x30 Startup
0x31 Shutdown
0x3b version
ox43 K2 Transactions
0x47 Query
0x4A OSQL7
ox5c OKOD
ox5e Query
ox60 LOB operations
ox62 ONDY
ox67 Transaction – end
ox68 Transaction – begin
ox69 OCCA
ox6d startup
ox51 Logon (present password)
ox52 Logon (present username)
0x73 Logon(present password -sned AUTH_PASSWORD)
ox76 Logon (present username – request AUTH_SESSKEY)
0x77 Describe
ox7F OOTCM
ox8B OKPFC
其中某些函数的调用优先于身份验证–例如,版本(ox3B)TTI函数:
0x08 表示:”OK” — 由相应某个客户机的服务器发送。
ox11 表示扩展的TTI函数。这些事在更高版本的Oracle中被引入的,因此为了向下兼容,没有使用oxo3。
下面给出了一些函数代码:
ox6b Switch or Detach Session
ox78 Close
0x87 OSCID
0x9A OKEYVAL
0x20 在调用外部过程并且带有服务限制的情况下使用。
0x44 也在调用外部过程并且带有服务限制的情况下使用。
检查Oracle JDBC驱动(classes12.zip)并不是获得TNS协议句柄的最佳方法,最佳方法是用一个网络嗅探器从线路上抓取一些包,然后观察接下来发生的情况。
翻译源头: 书中一节《The Oracle Hackers Handbook》
书籍网站: http://flylib.com/books/en/2.680.1.1/1/
本文转载自http://www.askmaclean.com/,此网站翻译内容,而后吾转载过来,整理了下.