在进行深入探究之前,我们首先来探讨一个困扰太多人的简单概念。今天的讨论要涉及到两个“实体(entities)”,或者称为进程。第一个是服务器进程。根据使用者的语义的精确性以及这个术语的使用语境,“服务器”可以指的是数据库、数据库实例、数据库服务器进程、或者是这些软件运行其上的物理服务器。如果用网络路由的术语来讲的话,所有这些都会归结到一个指定了 IP 地址的机器。第二个进程是客户端进程。它是请求连接到数据库(或数据库服务)的进程。同样,根据使用的语义的精确性和语境,术语“客户端”可以指的是一个进程或一台物理的计算机,对于今天的讨论,它指的是进程。而且,这个进程可以运行于任何计算机中,包括当作服务器使用的计算机(要理解这一点)。此时,它仍然是一个客户端,只是碰巧运行在用作服务器的计算机上。
如果说你使用的是 sqlplus 的话,那么就可以使用如下命令启动 sqlplus 并连接到数据库:
C:> sqlplus scott/tiger@larry
诚然,输入这个命令后最先发生的事儿,和 Oracle 没有半毛钱的关系。首先,操作系统要找到那个称为 sqlplus 的可执行文件,把它载入到内存,再把命令行的剩余部分(scott/tiger@larry)传给它,它会看看用传进来的参数能做些什么。然后,sqlplus 认为适合这些参数的工作是,请求 TNS 连接到 “larry”,使用用户 ID ”scott"、口令“tiger”作为认证凭据。那么,TNS 就必须弄明白 larry 代表什么。要弄明白这一点,默认情况下,它就需要去查看一个称为 tnsnames.ora 的文件。因为我们还在发出请求的客户端上,这个文件肯定是在客户端的机器上。默认情况下,它可以在$ORACLE_HOME/network/admin 目录下找到。
简单说吧,假设 tnsnames 文件有如下内容:
- larry =
- (DESCRIPTION =
- (ADDRESS_LIST =
- (ADDRESS = (PROTOCOL = TCP)(HOST = myhost)(PORT = 1521))
- )
- (CONNECT_DATA =
- (SERVICE_NAME = curley)
- )
- )
TNS 会在你的 tnsnames.ora 文件中去找一个名称为 “larry” 的条目。找到以后,就会通过操作系统的常规的网络协议栈,使用(PROTOCOL = TCP)协议发送一个请求到(HOST = myhost) 主机上的(PORT = 1521)端口,请求一个到(SERVICE_NAME = curley)服务的连接。需要注意的是,它是从 tnsnames 文件的条目那个位置取得这些信息的。(这个条目称为“连接标识符”。)还应注意,这里所做的是,将别名 “larry” 解析成实际的目的地址信息。从这的角度来讲,tnsnames.ora 在 sqlnet 中所起的作用,和操作系统中 hosts 文件在标准网络协议栈中的作用是一样的。
主机(HOST = myhost)的网络地址是什么呢?当连接请求从 TNS 传递到标准的网络协议栈时,主机名称 “myhost” 会被解析成 IP 地址,需要用到本地的 hosts 文件、DNS、或是其他不太常用的机制。但也可以把 IP 地址硬写在 tnsnames.ora 中(HOST = 123.456.789.101)。
一旦 IP 确定下来,标准的网络传输过程会把消息传输给指定主机/IP地址的指定端口。理想的情况是,在主机 myhost 上配置了一个在相应端口进行监听的、Oracle 数据库的监听程序,且此监听知道服务 (SERVICE_NAME = curley) 的存在。如果这些条件都满足,那么,监听程序会派生出一个服务器进程,来充当客户端和数据库实例间的协调人。与这个服务器进程的通讯将会在由监听选定的另一个端口上进行。到这个时候,监听程序就可以退出对连接请求的处理过程了,并且继续在所配置的端口上等待进来的其他连接请求。
什么地方会出错?
首先,可能在 tnsnames 中根本就没有 laryy 这一项。这种情况下,会得到错误信息“ORA-12154: TNS:could not resolve the connect identifier specified” (中文环境下为:ORA-12154: TNS: 无法解析指定的连接标识符 == 译注)。以后,我会对找不到 “larry” 的各种原因做进一步的讲解,但毫无疑问,如果你接收到的是ORA-12154时, 那么可以肯定,对连接请求的处理也就到此为止了。试图探究监听方来解决此问题,那就纯是浪费时间了。如果打不了电话是因为不知道对方电话号码(找不到电话簿----“tnsnames.ora”,或者电话簿中没有你要拨电话的人----没有 larry 这一项),你就不能去找总机的毛病了。
可能找到了 “larry” 这一项,但主机名 “myhost” 不能解析成 IP 地址(可能是本地 hosts 文件中没有 主机名“myhost” 这一项)。这会导致产生如下错误:“ORA-12545: Connect failed because target host or object does not exist” (中文环境为:ORA-12545: 因目标主机或对象不存在, 连接失败 ---- 译注)。
还可能本地 hosts 文件中有 "larry" 这一项,但指定了一个错误的 IP 地址,这也会导致 “ORA-12545: Connect failed because target host or object does not exist” 错误。
IP 地址可能也是对的,但服务器上没有运行相应的监听,会报: “ORA-12541: TNS:no listener”(中文环境:ORA-12541: TNS: 没有监听程序----译注)。
也可能 IP 是对的,myhost 上也启了监听,但是在不同的端口上监听。这时会报“ORA-12560: TNS:protocol adapter error”(中文环境:ORA-12560: TNS: 协议适配器错误)。
可能 IP 地址是对的,myhost 上也启动了监听,也在指定的端口上监听,但监听程序无法识别服务 SERVICE_NAME = curley,错误是:“ORA-12514: TNS:listener does not currently know of service requested in connect descriptor” ( 中文环境:ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务)。
以上讲的是客户端的连接请求是如何到达监听程序的。那么连接过程的监听部分又是如何运作的呢?
监听很简单,它在服务器(而不是客户端)上运行,它的任务就是监听连接请求并在客户端和数据库实例间建立连接(即服务器进程)。一旦建立了连接,监听就撤出了。即使杀掉了监听进程,已有的连接都会继续存在。
监听是通过 listener.ora 来配置的,但即使没有这个文件,监听也还是能全部使用默认值来启动。监听常见的一个配置错误是指定 “HOST=localhost” 或 “HOST=127.0.01” 。这是一个不可路由的 IP 地址。主机名 localhost 和 IP 地址 127.0.0.1 总是指“我所在的那台机器”。因此,所有的计算机都会把自己看作 “localhost” 或 “127.0.0.1”。如果监听配置中使用了这个 IP 地址,那么监听就只能够接受来自它自己所在的那台机器的请求。如果在 tnsnames 文件中指定了这个地址,则请求会被指向到请求客户端所在的那台机器。这肯定不是你想要的。
受此文启发,我对后面的帖子有了些基本的想法,后面的每帖会关注在连接过程的一个步骤中产生的问题。后面会有一贴会用实例解构(解析)实际的 TNS 连接请求,以对各种影响因素进行演示和和验证。