转载请注明来源:http://blog.csdn.net/tingya
1.5.3错误处理
大型的系统程序的错误处理是十分重要的,APR作为一个通用库接口集合详细的说明了使用APR时如何进行错误处理。
1.5.3.1 错误码定义
错误处理的第一步就是定义返回码,包括“错误码和状态码分类”。APR的函数大部分都返回int类型作为返回码的,不过为了更明确易懂,APR在apr_errno.h中使用typedef int apr_status_t将其进行了重新定义。它在一起定义的还有apr所用的所有错误码和状态码。如果一个APR函数绝对的不可能出错,那么此时就允许不返回ap_status_t错误码,只需要返回void类型即可。不过APR中大部分的函数都是返回apr_status_t值。
APR中的返回码的定义并不是随意的,没有规则的。相反,APR给出了定义返回码的严格的规定。APR中根据返回信息的相似性将它们分为七大类,分别定义如下所示:
#define APR_OS_ERRSPACE_SIZE 50000
#define APR_SUCCESS 0
#define APR_OS_START_ERROR 20000
#define APR_OS_START_STATUS (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE)
#define APR_OS_START_USERERR (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE)
#define APR_OS_START_CANONERR (APR_OS_START_USERERR \
+ (APR_OS_ERRSPACE_SIZE * 10))
#define APR_OS_START_EAIERR (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE)
#define APR_OS_START_SYSERR (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE)
正常情况下,函数返回APR_SUCCESS作为成功标志。否则根据情况返回上述类别中的任一种。每一大类的返回信息又可以具体细分为实际的值。在Apache中,每一类返回信息所允许的数目由APR_OS_ERRSPACE_SIZE决定,目前为50000,APR_OS_CANONERR为500000。另一方面,APR_OS_START_ERROR、APR_OS_START_STATUS、APR_OS_START_USEERR、APR_OS_START_CANONERR、APR_OS_START_EAIERR和APR_OS_START_SYSERR,它们每个都拥有自己独自的偏移量,具体偏移量的值以及含义如下表描述:
错误名称
|
含义
|
0
|
每个平台都有0,但是都没有实际的定义,0又的确是一个errno value的offset,但是它是“匿名的”,它不像EEXIST那样有着可以“自描述”的名字。
|
APR_OS_START_ERROR
|
该定义是平台相关的,不同平台的值可能不同,它定义了APR中所允许的错误码的起始偏移量,即20000,这意味着所有的错误码值不能低于20000。至于错误码,它可以是导致APR函数失败的任何原因。在这个范围内定义的所有错误码形式都必须是APR_E*格式,比如APR_ENOSTAT、APR_ENOSOCKET、APR_ENOPOOL。该类别中允许定义最多50000种错误码。
|
APR_OS_START_STATUS
|
该定义也是平台相关的,它定义了APR中所允许的返回状态值的起始偏移量,即APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE,即70000开始。不过需要注意的是,状态值并不能表示失败还是成功。如果要表示返回成功,必须使用APR_SUCCESS返回。在这个范围的状态码形式都必须是APR_*格式,比如APR_DETACH、APR_INCHILD。
|
APR_OS_START_USERERR
APR_OS_START_USEERR
|
该定义也是平台相关的。当用户使用APR库的时候,如果它希望定义APR返回码之外的其余的自定义返回码,那么这些返回码必须从APR_OS_START_USEERR开始,即APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE,即从120000开始。
|
APR_OS_START_CANONERR
|
APR_OS_START_CANONERR is where APR versions of errno values are defined on systems which don't have the corresponding errno.对于这类返回码的定义通常如下:
#ifdef EEXIST
#define APR_EEXIST EEXIST
#else
#define APR_EEXIST (APR_OS_START_CANONERR + 2)
#endif
|
APR_OS_START_EAIERR
|
在使用socket编程的时候如果调用getaddrinfo()函数,该函数会返回一系列的以EAI_*开始的错误码,比如EAI_AGAIN,EAI_FAIL等等。这些不规则的错误码最终都要转换为APR中对应的返回码。这些转换码从APR_OS_START_EAIERR开始,最多允许50000个(当然事实上肯定没有这么多)。
|
APR_OS_START_SYSERR
|
由于APR必须保持跨平台的特性,因此不同的操作系统平台肯定有自己所独有的一些返回码,这些返回码不具有移植性,是与平台相关的。尽管如此,他们也必须转换为APR内部返回码。APR_OS_START_SYSERR指定了定义这些不具有移植性返回码的起始偏移,为720000,容量为50000。
|
各返回信息起始便移量及其区别可以用下图描述:
从上表可以看出,所有的APR定义的返回码都是从APR_OS_START_ERROR开始,那么0到APR_OS_START_ERROR之间将近20000个空位岂不是浪费了?事实上这部分空间并没有浪费。我们后面所描述的”native error”会占用这部分的空隙。
Apache中的返回码如下表所示:
错误名称
|
含义
|
值
|
APR_ENOSTAT
|
APR无法对一个文件执行stat操作
|
20001
|
APR_ENOPOOL
|
APR没有提供内存池来执行内存分配操作
|
20002
|
APR_EBADDATE
|
APR给出了一个无效的日期
|
20003
|
APR_EINVALSOCK
|
APR给出了一个无效的socket
|
20004
|
APR_ENOPROC
|
APR没有给定一个进程的结构
|
20005
|
APR_ENOTIME
|
APR没有给定一个时间结构
|
20006
|
APR_ENODIR
|
APR没有给定一个目录结构
|
20007
|
APR_ENOLOCK
|
APR没有给定一个互斥锁结构
|
20008
|
APR_ENOPOLL
|
APR没有给定一个Poll结构
|
20009
|
APR_ENOSOCKET
|
APR没有给定一个socket
|
20010
|
APR_ENOTHREAD
|
APR没有给定一个线程结构
|
20011
|
APR_ENOTHDKEY
|
APR没有给定一个线程Key结构
|
20012
|
APR_ENOSHMAVAIL
|
APR中没有更多的可用共享内存
|
20013
|
APR_EDSOOPEN
|
APR中无法打开一个DSO对象
|
20014
|
APR_EGENERAL
|
APR中的通常的错误
|
20015
|
APR_EBADIP
|
描述的IP地址错误
|
20016
|
APR_EBADMASK
|
描述的IP地址掩码错误
|
20017
|
APR_ESYMNOTFOUND
|
无法查找到请求symbo
|
20018
|
APR_INCHILD
|
程序正在执行子进程
|
70001
|
APR_INPARENT
|
程序正在执行父进程
|
70002
|
APR_DETACH
|
线程从主线程中被分离出来
|
70003
|
APR_NOTDETACH
|
线程尚未从主线程中分离出来
|
70004
|
APR_CHILD_DONE
|
子进程已经执行完毕
|
70005
|
APR_CHILD_NOTDONE
|
子进程尚未执行完毕
|
70006
|
APR_TIMEUP
|
执行操作超时
|
70007
|
APR_INCOMPLETE
|
The operation was incomplete although some processing was performed and the results are partially valid
|
70008
|
APR_BADCH
|
Getopt函数查找到一个不在选项字符串中的选项
|
70012
|
APR_BADARG
|
Getopt发现一个选项缺少参数,而在选项字符串中该选项必须指定
|
70013
|
APR_EOF
|
APR已经到达文件的末尾
|
70014
|
APR_NOTFOUND
|
APR在poll结构中无法发现socket
|
70015
|
APR_ANONYMOUS
|
APR正在使用匿名的共享内存
|
70019
|
APR_FILEBASED
|
APR正在使用文件名作为共享内存的key
|
70020
|
APR_KEYBASED
|
APR正在使用共享key作为共享内存的key
|
70021
|
APR_EINIT
|
70022
|
|
APR_ENOTIMPL
|
在该平台上,该APR函数尚未实现
|
70023
|
APR_EMISMATCH
|
输入的两个密码不匹配
|
70024
|
APR_EABSOLUTE
|
给定的路径值是绝对路径
|
70019
|
APR_ERELATIVE
|
给定的路径是相对路径
|
70020
|
APR_EINCOMPLETE
|
给定的路径既不是相对路径也不是绝对路径
|
70021
|
APR_EABOVEROOT
|
给定的路径在跟路径上
|
70022
|
APR_EBUSY
|
给定的互斥锁正忙,已经被锁定
|
70025
|
APR_EPROC_UNKNOWN
|
该进程无法被APR所识别
|
70024
|
有一点必须明确的是返回码并不一定总是错误码。如果你的函数返回多个值,它们中的每一个都意味着执行成功,但是它们的值却不一样,或者你的函数仅仅返回成功或者失败两种情况,那么APR中通常仍然会返回一个apr_status_t值。
在第一种情况下,即如果执行成功具有多种状态,那么可以为每一个状态定义一个APR返回状态码,典型的例子就是apr_proc_wait函数,它用于等待子进程结束,它会返回三种情况:APR_CHILDDONE表示子进程已经执行完毕;APR_CHILDNOTDONE表示子进程尚未执行完毕;错误码则意味着等待子进程失败。对于前两种返回不能称之为失败,它们都是成功返回,只是返回状态不一样而已,为此APR中定义两个状态码表示返回状态,记住不是错误码。
对于第二种情况,即执行成功后仅有一种状态,那么如果执行成功,APR中通常返回APR_SUCCESS,而不是什么都不返回;如果执行失败,则定义新的APR状态码来描述这种失败。比如apr_compare_users函数,它返回APR_SUCCESS表示失败,同时定义APR_EMISMATCH和其余错误码表示失败。
根据上面的原则,你就会发现APR中的函数很少有返回类型为void或者void*的。更多的都是返回apr_status_t。
APR中所有的错误码的定义在apr_errno.h中都可以找到。当APR函数中发生错误的时候,这些函数必须返回一个错误码。如果这些错误是在系统调用错误,那么APR将使用系统调用返回的错误码errno作为返回码原样返回,比如:
if(open(fname,oflags,0777)<0)
return errno;
对于系统调用,除了直接返回系统错误码之外,另外一种策略就是使用新的APR错误码替代原始的系统错误码,比如:
if (CreateFile(fname, oflags, sharemod, NULL,
createflags, attributes, 0) == INVALID_HANDLE_VALUE
return (GetLAstError() + APR_OS_START_SYSERR);
上面的两个例子在不同的平台上实现了相同的功能。显而易见,即使在两个平台上存在的潜在问题都是一样的,那么也会导致返回截然不同的错误码。不过对于这两种情况APR都是支持的。事实上APR的观点是,当一个错误发生的时候,程序通常是记录该错误并且继续往下执行,默认情况下它并不会去尝试解决发生的错误。不过这并不意味着APR根本不捕获错误并且提供解决方案。事实上,在后面的部分我们会看到APR中如何处理错误。
1.5.3.2 返回码信息映射
大部分情况下,状态码主要用于系统内部使用,因此它的含义隐晦,对于用户影响不是特别的大,但是错误码则不一样。用户更多的是希望系统返回足够多的信息以便直到发生错误的原因,从而进行跟踪和调试。因此这种情况下,如果如果仅仅返回一个整数给用户,用户可能会莫名其妙,一头雾水。最好的方法就是能够将该返回码所代表的实际的含义以字符串的形式返回出去。事实上大部分操作系统平台都提供了这种对应函数,比如stderror。APR中使用apr_strerror函数将上述的返回码转换为实际的字符串信息:
APR_DECLARE(char *) apr_strerror(apr_status_t statcode, char *buf,
apr_size_t bufsize)
statcode是需要转换的返回码,转换后的字符串保存在缓冲区buf中,函数所允许的字符串的长度由bufsize控制。
对于不同的返回码,APR采取不同的转换策略:
■ 系统错误码(statcode< APR_OS_START_ERROR)
这类错误码APR中称之为”native error”,即这些错误码并不是APR定义的,而是系统返回的。比如open函数的返回码就应该算”native error”。对于这类错误码,APR的处理就是直接使用stderror_r函数返回系统提示的消息,如果找不到该系统错误码,返回”APR does not understand this error code”信息。之所以不使用stderror是因为stderror不是线程安全的。如果平台能够实现线程安全的stderror函数,比如Solaris, OS/390,那么你也可以使用stderror,否则不要这么做。
这类”native error”通常小于20000,因此它们会使用APR_OS_START_ERROR之前的空隙。
■ APR定义返回码(APR_OS_START_ERROR <= statcode <= APR_OS_START_USERERR)
这类返回码通常是APR定义并使用的,因此APR本身必须能够维持这些返回码和返回信息之间的对应关系。APR中采取的是最原始的”switch/case”方法来对传入的返回码逐一进行判断:
static char *apr_error_string(apr_status_t statcode)
{
switch (statcode) {
case APR_ENOPOOL:
return "A new pool could not be created.";
case APR_EBADDATE:
return "An invalid date has been provided";
case APR_EINVALSOCK:
return "An invalid socket was returned";
case APR_ENOPROC:
return "No process was provided and one was required.";
......
}
因此如果需要了解APR_ENOPOOL返回码的确切含义,只需要使用语句printf(“%s”,apr_error_string(APR_ENOPOOL))即可。
■ APR自定义返回码(APR_OS_START_USERERR <= statcode <= APR_OS_START_EAIERR)
■ EAI错误码(APR_OS_START_EAIERR <= statcode <= APR_OS_START_SYSERR)
该范围内的错误码主要对应getaddrinfo函数返回的EAI_*系列错误码。因此在对statcode进行调整后直接调用gai_strerror()返回对应的信息即。如果操作系统不支持gai_strerror函数,那么直接返回"APR does not understand this error code"。
■ 平台相关错误码(APR_OS_START_SYSERR <= statcode)
这类错误码总是与平台相关的,APR返回码与实际的错误码之间保持下面的关系:
APR_Error = APR_OS_START_SYSERR + 系统错误码
由于这类错误码与平台相关,因此处理也是与平台相关的。
1)、对于WINDOW平台而言,所有的Window平台所特有的错误码及实际含义都保存在数组gaErrorList中:
static const struct {
apr_status_t code;
const char *msg;
} gaErrorList[] = {
WSAEINTR, "Interrupted system call",
WSAEBADF, "Bad file number",
WSAEACCES, "Permission denied",
……
}
因此处理过程就很简单,一旦获取了错误码比如WSAEACCES后通过查找gaErrorList数组就可以获取其实际含义。返回后的字符串使用FormatMessage格式化输出。
2)、对于Unix平台而言主要是由于Linux在调用诸如gethostbyname或者gethostbyaddr等函数时候会返回一些特有的错误码,比如HOST_NOT_FOUND、NO_ADDRESS、NO_DATA、NO_RECOVERY、TRY_AGAIN等。Linux专门提供了hstrerror函数获取这些错误码的实际含义。因此对这类错误码的处理如果系统实现了hstrerror,则调用hstrerror处理,否则使用最原始的switch/case进行处理:
switch(err) {
case HOST_NOT_FOUND:
msg = "Unknown host";
break;
case NO_ADDRESS:
msg = "No address for host";
break;
case NO_DATA:
msg = "No address for host";
break;
default:
msg = "Unrecognized resolver error";
}
3)、另一种需要考虑的就是OS/2。由于OS/2不是我们的重点,此处不
相关推荐
http://apache.mirror.phpchina.com/apr/apr-1.3.3-win32-src.zip http://apache.mirror.phpchina.com/apr/apr-util-1.3.4-win32-src.zip http://apache.mirror.phpchina.com/apr/apr-iconv-1.2.1-win32-src.zip
Apache可移植运行时库(APR)是Apache软件基金会自主开发和维护的一套运行时库,其主要目的是为应用程序提供一个可移植的、与平台无关的底层服务层。APR通过使用底层的、跨平台的库来实现一系列功能,包括文件系统...
APR(Apache portable Run-time libraries,Apache可移植运行库)的目的如其名称一样,主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库。在早期的Apache版本中,应用程序本身必须能够处理...
APR(Apache portable Run-time libraries,Apache可移植运行库)的目的如其名称一样,主要为上层的应用程序提供一个可以跨越多操作系统平台使用的底层支持接口库。在早期 的Apache版本中,应用程序本身必须能够处理...
这些库是Apache正常运行所必需的。 2. **在上位机(Host)上编译安装Apache运行环境**: 在这个阶段,你需要在开发环境中(通常是x86架构的PC)构建Apache及其依赖库。这包括: - apr-1.4.8:通过`./configure --...
APR的设计目标是让Apache在跨平台环境中保持一致的行为,确保代码的可移植性。在Linux环境下,APR利用了系统的特性,如socket编程接口、信号处理等,使Apache能高效地与操作系统交互。 **APR-Util** APR-Util是APR...
apr是Apache Portable Runtime的缩写,是一个Apache可移植运行库。编译apr需要执行以下步骤: 1. 解压apr-1.4.6.tar.gz文件 2. 进入apr-1.4.6目录,执行configure命令 3. 执行make命令 4. 执行make install命令 四...
软件包介绍:apr :Apache可移植运行库,给apache模块中添加组件和开发工具 cyrus-sasl: 协议认证模块,认证apache可调用的协议 expat-devel:编译扩展环境,在编译安装软件包时,添加系统信息 libdb-devel:数据库...
### 各版本Apache移植知识点详解 #### 一、编译环境与工具介绍 根据文档描述,本篇将针对不同版本的Apache与PHP进行ARM架构下的编译配置与移植方法的探讨。首先,需要明确编译环境的具体配置: - **操作系统**:...
这个库的设计目标是提供一个统一的、高度优化的API,使得开发者能够编写出可移植性强、性能优异的软件。APR在Apache项目中的作用至关重要,因为它隐藏了不同操作系统之间的差异,使得服务器软件可以在多种操作系统上...
Apache Portable Runtime(APR)是Apache HTTP服务器项目的基础库,它为各种操作系统提供了一个统一的接口,使软件开发人员能够在不同的平台上编写可移植的代码。APR提供了诸如文件I/O、网络连接、内存管理、线程...
Apache Portable Runtime(简称APR),是由Apache软件基金会开发的一个跨平台库,其主要目的是为开发者提供一组封装了底层操作系统特性的API接口,以便于应用程序能够更好地在不同的操作系统上进行移植。APR的核心...
APR 是Apache HTTP Server项目的基础库,它提供了操作系统级别的接口,包括文件操作、网络通信、内存管理等,确保了Apache在不同操作系统上的可移植性。APR-Utils则是一系列基于APR的实用工具集合,用于支持更高级别...
APR的目的是使Apache服务器和其他基于APR的应用程序在不同平台上具有良好的移植性。 3. **APR-Util**: APR-Util是APR的扩展库,包含了诸如数据库连接、加密、压缩、文本处理等功能。它为开发者提供了许多实用工具,...
Apache作为一款广泛使用的开源Web服务器软件,其运行机制主要包括几个关键部分:核心引擎、模块加载系统、多处理模块(MPM)、以及可移植运行库(APR)。深入理解这些组成部分有助于更好地管理和优化Apache服务器。 ...
APR包含了I/O操作、内存管理、线程同步等底层功能,为Apache提供了高度的移植性和性能。安装APR的步骤通常包括下载源码、解压、配置、编译和安装: 1. 下载apr源码包。 2. 使用tar命令解压缩:`tar -zxvf apr-x.x.x...
本文将详细介绍Apache 2.2.9版本在ARM架构下的移植过程,包括下载、配置、编译以及安装等步骤,最终成功地在ARM板端运行Apache。 #### 二、准备工作 在进行Apache的移植之前,我们需要准备好必要的工具和环境。...
Apache可移植运行时(APR)是Apache Web服务器的支持库。它提供了一组映射到基础操作系统(OS)的应用程序编程接口(API)。如果操作系统不支持特定功能,则APR将提供仿真。因此,程序员可以使用APR使程序可跨不同...
标题中的"apr-1.4.8.tar.gz"和"apr-util-1.5.4.tar.gz"是两个开源软件库的源代码压缩文件。它们主要用于Apache Portable Runtime(APR)和...正确地安装和使用这些库可以极大地提升开发效率并保证代码的可移植性。
APR,全称为Apache Portable Runtime(Apache可移植运行时库),是Apache HTTP服务器项目的核心组件之一,用于提供操作系统级别的服务,如内存管理、线程、网络接口等。它旨在跨平台,确保在不同操作系统上的一致性...