新闻动态 news

如何利用系统的errno来排错

◆问题描述:

 在苏州的特色平台与自助设备进行联机交易的时候,如果特色平台返回的数据比较大(实际环境这一返回数据的大小达到了250131字节),eas在发送返回数据时报错,错误信息如下:
 11-10 15:59:30.114 eixsocket.c L=808 P=676344 E=32 id=37660                    
 发送长度(250139)的发送响应数据给(自助设备打印票据)出错!

◆问题主题词:系统错误 errno 排错技巧

◆回答:

出现类似的错误,很多程序员都面临着困惑,类似的问题如何来查呢?

 首先我们来回顾一下一些系统函数的调用返回,以fopen为例,在成功时,fopen返回一个指向该文件的句柄,而出错时,fopen返回NULL,NULL这一返回值并不能帮助用户有效的找到错误的原因,因为我们知道fopen可能出错的原因很多,例如:文件没有读权限、文件不存在、无效的文件名、内存不足等等,我们如何来确定这一原因呢?

 为了解决这一问题,系统提供了errno这一全局变量来说明具体的错误原因,一般而言,该全局变量定义在/usr/include/errno.h这一头文件中,当一个系统函数(如:libc中的函数)出现调用错误时,其会将具体的错误原因通过变量errno来返回,这样开发者就可以通过errno的值来确定具体的错误原因所在,在/usr/include/sys下的errno.h中,列出了errno所可能出现的各种取值情况,如:

#define EPERM       1   /* Not owner                */
#define ENOENT      2   /* No such file or directory        */
#define ESRCH       3   /* No such process          */
……
 这样我们就可以根据errno的取值,来判断大致的错误原因,当然,在出现错误时,我们也可以通过调用函数strerror(errno)来输出具体的错误原因,这样排查错误就更加直接。

 为了查错方便,在eix/eas的日志中,我们也将这一错误号写入到了日志的系统信息中,在前面的日志信息中,E=32其中的32就是调用出错时errno的返回值。

 虽然通过对errno这一类似响应码的(函数的返回值判断可以视成功标志)字段的判断,我们可以得到调用大致出错的原因。然而由于系统提供的调用函数比较多,而errno的出错取值却只有100多个(个别操作系统下,可能会达到200个),而出错的可能性却远远不止200种,这就导致了一个情况,errno在不同的调用中其错误含义是不同的,这时,就需要我们通过man fopen来确定其对应的错误号所标识的真正错误,例如,我们在man fopen时可以看到其出错的情况如下:
  [EINTR]
          A signal was caught during the open system call.

  [EINVAL]
          The value of oflag is not valid.

  [EIO]   A hangup or error occurred during a STREAMS open.

  [EISDIR]
          The named file is a directory and oflag includes O_WRONLY or O_RDWR

  [EMFILE]
          OPEN_MAX descriptors are open in the current process.

 其中的EINTR、EINVAL、EIO、EISDIR、EMFILE对应的就是errno各种取值的宏定义,这一定义正是在/usr/include/sys/errno.h中来实现的。