TNS(ORACLE)协议分析
由于TNS是Oracle的私有协议,并非像TCP/IP那样有公开的、官方的RFC文档,此说明是基于网络流量分析、文档片段和行业共识重建的。不同版本在高级功能(如加密、压缩)上差异显著,但基础包结构保持一致。
1. 引言
Transparent Network Substrate (TNS) 是Oracle客户端、数据库服务器及其他组件(如监听器)之间通信的专有网络协议。它提供了一个统一的接口,独立于底层网络传输协议(如TCP/IP、IPC、SDP),负责建立连接、交换数据和控制信息。
本文档描述了TNS协议在Oracle数据库版本 9.2.0.2, 11.2.0.4, 12.2.0.1, 和 19.3.0.0 中使用的数据包格式、数据类型和核心通信流程。重点在于基于TCP/IP传输时的底层字节级描述。
2. 协议概述
TNS通信是基于消息的。所有消息都被封装在一个TNS数据包(Packet)中。通信由一个连接握手(握手包)初始化,随后是一系列的数据包交换。每个数据包包含一个包头(Header)和可选的数据部分(Data Area)。
3. 通用数据包结构
每个TNS数据包都具有以下固定结构:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Length | Packet Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Type |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Reserved Field (0x00) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
/ Data Area (Variable) /
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.1. 包头(Header)字段详解
Packet Length (16位,无符号大端序整数)
定义了整个TNS数据包的总长度,包括16字节的包头本身。
值范围:`0x0000` - `0xFFFF` (0 - 65535字节)。实际数据区最大为 65519 字节。
Packet Checksum (16位,无符号大端序整数)
整个数据包(包头+数据区)的校验和。算法是简单的16位和(16-bit sum)。
如果未使用校验和,此字段设置为 `0x0000`。
Packet Type (8位,但占用32位空间)
定义数据包的类型。这是一个单字节的值,但存储在32位(4字节)的空间中。**高24位必须为0**。
关键类型包括:
`0x01` (CONNECT)
`0x02` (ACCEPT)
`0x06` (REFUSE)
`0x0B` (RESEND)
`0x0C` (REDIRECT)
`0x0E` (DATA)
`0x0F` (NULL) - Keep-Alive包
`0x11` (ABORT)
`0x13` (MARKER) - 用于协议特性协商(12c+)
Reserved Field (24位)
保留字段,必须设置为 `0x000000`。
Header Checksum (16位,无符号大端序整数)**
仅针对前面12字节包头(从Packet Length到Reserved Field)计算的16位和校验和。
如果未使用,设置为 `0x0000`。
3.2. 数据区(Data Area)
数据区的结构和内容完全取决于`Packet Type`。例如,`CONNECT`和`ACCEPT`包包含连接描述符信息,而`DATA`包包含实际的SQL语句或结果集。
4. 连接建立流程(三次握手)
TNS使用一个三次握手来建立连接。
1. 客户端 -> 服务器: CONNECT Packet (Type=0x01)**
数据区**包含一个**连接描述符(Connect Descriptor)**。这是一个复杂的结构,包含目标数据库服务名、发起方和接收方的TNS协议版本、全局数据库名、字符集、协议特性协商数据(如`SDU`/`TDU`大小)等。
版本特定行为:
9.2.0.2/11.2.0.4: 发送客户端支持的TNS版本(例如,`0x0134` for 11.2)。
12.2.0.1/19.3.0.0: 包含更丰富的特性协商数据(`(CONNECT_DATA=(...)(UR=A)...)`),支持更高级的负载均衡和故障转移特性。
- 服务器 -> 客户端: ACCEPT Packet (Type=0x02) 或 REFUSE Packet (Type=0x06)
ACCEPT: 服务器同意连接。数据区包含服务器选择的TNS版本、`SDU`大小以及会话参数。
REFUSE: 服务器拒绝连接。数据区包含一个错误代码和消息。
3. 客户端 -> 服务器: (可选) Protocol Negotiation**
在某些情况下(例如重定向或高级特性协商),客户端可能会发送额外的数据包来确认参数。
5. 数据交换 (DATA Packets, Type=0x0E)
连接建立后,所有SQL对话都通过`DATA`包进行。`DATA`包的数据区包含一个或多个TNS数据头(TNS Data Header),后跟实际的应用数据。
5.1. TNS数据头结构
在`DATA`包内部,数据被组织成TNS Data Headers。每个Header描述其后跟随的数据的类型和用途。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data Flags | Data Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Data Flags (16位,大端序)
位掩码,指示数据的性质。
常见标志:
`0x0000`: 普通数据段
`0x0001`: 数据流的开始 (SQL语句开始)
`0x0002`: 数据流的结束 (SQL语句结束)
`0x0020`: 等待服务器响应 (``TTC`` ``Piggyback`` ``Status``)
`0x8000`: 最后一个数据包
Data Length (16位,无符号大端序整数)
紧随此Header之后的应用数据的长度。
应用数据本身使用Oracle的TTC(Two-Task Common)协议进行格式化,该协议负责将数据类型、游标状态、行数据等编码为字节流。TTC的详细描述超出了本文档的范围。
6. 版本差异和高级特性
6.1. 加密与安全 (Across Versions)
9.2.0.2: 支持原生加密(`(ENCRYPTION=...)`),但算法较弱(如RC4_40)。`SQLNET.ENCRYPTION_CLIENT`和`SQLNET.ENCRYPTION_SERVER`参数控制。
11.2.0.4: 引入了更强的加密套件(AES192, AES256)。开始推动使用`TCPS`。
12.2.0.1 / 19.3.0.0: 关键变化。默认启用Native Network Encryption和Checksumming(如果`sqlnet.ora`中未明确设置,由`SQLNET.ENCRYPTION_SERVER`的默认值`REQUESTED`驱动)。强烈推荐使用`TCPS`。支持更现代的算法。
6.2. 协议协商 (12.2.0.1+)
12c引入了更复杂的特性协商机制。`CONNECT`数据包中包含`(UR=A)`等字段,允许客户端和服务器就协议特性(如大文件支持、会话迁移、负载均衡 advisory)进行协商。这通过`MARKER`包(Type=0x13)和扩展的`DATA`包标志来实现。
6.3. 数据单元大小 (SDU)
所有版本都协商`SDU`(Session Data Unit)大小,它影响单个`DATA`包的有效载荷大小。
默认大小通常为8192字节。可以在`tnsnames.ora`和`listener.ora`中配置更大的值(例如`SDU=32767`)以提高大批量数据传输的效率。12c和19c对大`SDU`的支持更好。