从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。又例如,当一个系统调用(比如fork)因为没有足够的资源(比如虚拟内存)而执行失败,返回EAGAIN提示其再调用一次(也许下次就能成功)。

Linux - 非阻塞socket编程处理EAGAIN错误

在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这是什么意思?

这表明你在非阻塞模式( 比如epoll的ET模式下设置recv,对应的fd文件描述符设置为非阻塞 )下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。对非阻塞socket而言,EAGAIN不是一种错误。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。

EINTR错误:

慢系统调用(slow system call):此术语适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。如:若没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。

  • EINTR错误的产生:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误。例如:在socket服务器端,设置了信号捕获机制,有子进程,当在父进程阻塞于慢系统调用时由父进程捕获到了一个有效信号时,内核会致使accept返回一个EINTR错误(被中断的系统调用)。

当碰到EINTR错误的时候,可以采取有一些可以重启的系统调用要进行重启,而对于有一些系统调用是不能够重启的。例如:accept、read、write、select、和open之类的函数来说,是可以进行重启的。不过对于套接字编程中的connect函数我们是不能重启的,若connect函数返回一个EINTR错误的时候,我们不能再次调用它,否则将立即返回一个错误。针对connect不能重启的处理方法是,必须调用select来等待连接完成。

对于socket接口(指connect/send/recv/accept..等等后面不重复,不包括不能设置非阻塞的如select),在阻塞模式下有可能因为发生信号,返回EINTR错误,由用户做重试或终止。

但是,在非阻塞模式下,是否出现这种错误呢?
对此,重温了系统调用、信号、socket相关知识,得出结论是:不会出现。

  1. 信号的处理是在用户态下进行的,也就是必须等待一个系统调用执行完了才会执行进程的信号函数,所以就有了信号队列保存未执行的信号;
  2. 用户态下被信号中断时,内核会记录中断地址,信号处理完后,如果进程没有退出则重回这个地址继续执行;

socket接口是一个系统调用,也就是即使发生了信号也不会中断,必须等socket接口返回了,进程才能处理信号。
也就是,EINTR错误是socket接口主动抛出来的,不是内核抛的。socket接口也可以选择不返回,自己内部重试之类的..

那阻塞的时候socket接口是怎么处理发生信号的?

举例socket接口,例如recv接口会做2件事情,

  1. 检查buffer是否有数据,有则复制清除返回;
  2. 没有数据,则进入睡眠模式,当超时、数据到达、发生错误则唤醒进程处理;

socket接口的实现都差不了太多,抽象说,

  1. 资源是否立即可用,有则返回
  2. 没有,就等...

1.这个时候不管有没信号,也不返回EINTR,只管执行自己的就可以了
2.采用睡眠来等待,发生信号的时候进程会被唤醒,socket接口唤醒后检查有无未处理的信号(signal_pending)会返回EINTR错误。

所以
socket接口并不是被信号中断,只是调用了睡眠,发生信号睡眠会被唤醒通知进程,然后socket接口选择主动退出,这样做可以避免一直阻塞在那里,有退出的机会。非阻塞时不会调用睡眠。

在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。EAGAIN和EWOULDBLOCK等效!从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误EAGAIN,提示你.. struct sockaddr_in client_addr; int sin_size,portnumber; char hello[]="Hello! Are You Fine?\n"; if(argc!=2) fpr int f(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); if((portnumber=atoi(argv[1]))<0) fpr int f(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); /* 服务器端开始建立socket 描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) fpr int f(stderr,"Socket error:%s\n\a",strerror( errno )); exit(1); /* 服务器端填充 sockaddr 结构 */ bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); /* 捆绑sockfd 描述符 */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))== fpr int f(stderr,"Bind error:%s\n\a",strerror( errno )); exit(1); /* 监听sockfd 描述符 */ if(listen(sockfd,5)==-1) fpr int f(stderr,"Listen error:%s\n\a",strerror( errno )); exit(1); while(1) /* 服务器阻塞,直到客户程序建立连接 */ sin_size=sizeof(struct sockaddr_in); if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size ))==-1) fpr int f(stderr,"Accept error:%s\n\a",strerror( errno )); exit(1); fpr int f(stderr,"Server get connection from %s\n", inet_ntoa(client_addr.sin_addr)); if(write(new_fd,hello,strlen(hello))==-1) fpr int f(stderr,"Write Error:%s\n",strerror( errno )); exit(1); /* 这个通讯已经结束 */ close(new_fd); /* 循环下一个 */ close(sockfd); exit(0); /******* 客户端程序 client.c ************/ #include <stdlib.h>; #include <stdio.h>; #include < errno .h>; #include <string.h>; #include <netdb.h>; #include <sys/types.h>; #include <netinet/in.h>; #include <sys/socket.h>; int main( int argc, char *argv[]) int sockfd; char buffer[1024]; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes; if(argc!=3) fpr int f(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); if((host=gethostbyname(argv[1]))==NULL) fpr int f(stderr,"Gethostname error\n"); exit(1); if((portnumber=atoi(argv[2]))<0) fpr int f(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); /* 客户程序开始建立 sockfd 描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) fpr int f(stderr,"Socket Error:%s\a\n",strerror( errno )); exit(1); /* 客户程序填充服务端的资料 */ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(portnumber); server_addr.sin_addr=*((struct in_addr *)host->;h_addr); /* 客户程序发起连接请求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr) )==-1) fpr int f(stderr,"Connect Error:%s\a\n",strerror( errno )); exit(1); /* 连接成功了 */ if((nbytes=read(sockfd,buffer,1024))==-1) fpr int f(stderr,"Read Error:%s\n",strerror( errno )); exit(1); buffer[nbytes]='\0'; pr int f("I have received:%s\n",buffer); /* 结束通讯 */ close(sockfd); exit(0); int sockfd,new_fd; struct sockaddr_in my_addr; //服务器网络地址结构体 struct sockaddr_in their_addr; //客户端网络地址结构体 int sin_size; if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { perror("socket"); exit(1); } my_addr.sin_family=AF_INET; //设置为 IP 通信 my_addr.sin_port=htons(MYPORT); //服务器端口号 my_addr.sin_addr.s_addr=INADDR_ANY; //服务器 IP 地址--允许连接到所有本地地址上 bzero(&(my_addr.sin_zero),8); //置零 &hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;&hell ip ;
Linux 环境下开发经常会碰到很多错误(设置 errno ),其中 EAGAIN 是其中比较常见的一个错误(比如用在非阻塞操作中)。在man手册关于read的解释如下: RETURN VALUE     On success, the number of bytes read is returned(zero indicates end of file), and the file position is    advanced by this number. It is not an error if thi
E INT R:指操作被中断唤醒,需要重新读/写   在 Linux 环境下开发经常会碰到很多错误(设置 errno ),其中 EAGAIN 是其中比较常见的一个错误(比如用在非阻塞操作中)。 从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。 EAGAIN 和EWOULDBLOCK是 linux 环境下的两个错误码,在非阻塞IO中经常会碰到,对新手而言,如何处理这两个值非常头疼。如果处理不当,很容易导致程序异常。 EAGAIN 的官方定义: “Resource temporarily unavailable.” The call might
一.概念介绍网络程序分为服务端程序和客户端程序。服务端即提供服务的一方,客户端为请求服务的一方。但实际情况是有些程序的客户端、服务器端角色不是这么明显,即互为客户端和服务端。我们编写网络程序时,一般是基于 TCP 协议或者UDP协议进行网络通信的。 TCP :(Transfer Control Protocol)传输控制协议是一种面向连接的协议, 当我们的网络程序使用这个协议的时候,网络可以保证我们的客户端和服务端之间的传输是可靠的。UDP:(User Datagram Protocol)用户数据报协议是一种非面向连接的协议, 这种协议并不能保证我们的网络程序的连接是可靠的。我们编写的网络程序具体采用
netstat 命令 netstat是用来显示网络的连接,路由表和接口统计等网络的信息.netstat有许多的 选项 我们常用的选项是 -an 用来显示详细的网络状态.至于其它的选项我们可以使用帮 助手册获得详细的情况. telnet telnet是一个用来远程控制的程序,但是我们完全可以用这个程序来调试我们的服务端程 序的. 比如我们的服务器程序在监听 8888 端口,我们可以用 telnet localhost 8888来查 看服务端的状况. TCP (Transfer Control Protocol)传输控制协议是一种面向连接的协议,当我们的网络程 序使用 这个协议的时候,网络可以保证我们的客户端和服务端的连接是可靠的,安全的. UDP(User Datagram Protocol)用户数据报协议是一种非面向连接的协议,这种协议并不能保证 我们的网络程序的连接是可靠的,所以我们现在编写的程序一般是采用 TCP 协议的 socket int socket( int domain, int type, int protocol) domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX 和AF_INET 等). AF_UN IX 只能够用于单一的 Unix 系统进程间通信,而 AF_INET 是针对 Int ernet的,因而可以允许在 远程 主机之间通信(当我们 man socket 时发现 domain 可选项是 PF_*而不是AF_*,因为 glibc 是 posix 的实现 所以用 PF代替了 AF,不过我们都可以使用的). type:我们网络程序所采用的通讯协议(SOCK_STREAM,SOCK_DGRAM 等) SOCK_STREAM 我们用的是 TCP 协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM 表明我们用的是 UDP协议,这样只会提供定长的,不可靠,无连接的通信. protocol:由于我们指定了 type,所以这个地方我们一般只要用 0 来代替就可以了 sock et 为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1,看 errno 可知道出错 的详细情况. int bind( int sockfd, struct sockaddr *my_addr, int addrlen) sockfd:是由socket调用返回的文件描述符. addrlen:是 sockaddr结构的长度. my_addr:是一个指向 sockaddr的指针. 在< linux /socket.h>;中有 sockaddr的定义 struct sockaddr{ unisgned short as_family; char sa_data[14]; 不过由于系统的兼容性,我们一般不用这个头文件,而使用另外一个结构(struct sock addr_in) 来代替.在< linux /in.h>;中有 sockaddr_in 的定义 struct sockaddr_in{ unsigned short sin_family; unsigned short int sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; 我们主要使用 Int ernet所以 sin_family 一般为 AF_INET,sin_addr设置为 INADDR_ANY 表 示可以 和任何的主机通信,sin_port 是我们要监听的端口号.sin_zero[8]是用来填充的 .. bind 将本地的端口同 socket返回的文件描述符捆绑在一起.成功是返回 0,失败的情况和 socket一样 listen int listen( int sockfd, int backlog) sockfd:是 bind 后的文件描述符. backlog:设置请求排队的最大长度.当有多个客户端程序和服务端相连时, 使用这个表示 可以介绍的排队长度. listen函数将 bind 的文件描述符变为监听套接字.返回的情况和 b ind 一样. accept int accept( int sockfd, struct sockaddr *addr, int *addrlen) sockfd:是 listen后的文件描述符. addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了. bind,li sten和 accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个 客户程序发出了连接. accept 成功时返回最后的服务器端的文件描述符,这个时候服务 器端可以向该描述符写信息了. 失败时返回-1 connect int connect( int sockfd, struct sockaddr * serv_addr, int addrlen) sockfd:socket返回的文件描述符. serv_addr:储存了服务器端的连接信息.其中 sin_add 是服务端的地址 addrlen:serv_addr的长度 connect函数是客户端用来同服务端连接的.成功时返回 0,sockfd 是同服务端通讯的文件 描述符 失败时返回-1. 总的来说网络程序是由两个部分组成的--客户端和服务器端.它们的建立步骤一般是: socket-->;bind-->;listen-->;accept socket-->;connect 字节转换函数 在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的, 比如 i386 芯 片是低字节在内存地址的低端,高字节在高端,而 alpha 芯片却相反. 为了统一起来,在 Li nux 下面,有专门的字节转换函数. unsigned long int htonl(unsigned long int hostlong) unsigned short int htons(unisgned short int hostshort) unsigned long int ntohl(unsigned long int netlong) unsigned short int ntohs(unsigned short int netshort) 在这四个转换函数中,h 代表 host, n 代表 network.s 代表 short l 代表 long 第一个函 数的意义是将本机器上的 long 数据转化为网络上的 long. 其他几个函数的意义也差不多 IP 和域名的转换 在网络上标志一台机器可以用 IP 或者是用域名.那么我们怎么去进行转换呢? struct hostent *gethostbyname(const char *hostname) struct hostent *gethostbyaddr(const char *addr, int len, int type) 在<netdb.h>;中有 struct hostent的定义 struct hostent{ char *h_name; /* 主机的正式名称 */ char *h_aliases; /* 主机的别名 */ int h_addrtype; /* 主机的地址类型 AF_INET*/ int h_length; /* 主机的地址长度 对于 IP 4 是 4 字节 32 位*/ char **h_addr_list; /* 主机的 IP 地址列表 */ #define h_addr h_addr_list[0] /* 主机的第一个 IP 地址*/ gethostbyname 可以将机器名(如 linux .yessun.com)转换为一个结构指针.在这个结构里 面储存了域名的信息 gethostbyaddr可以将一个 32 位的 IP 地址(C0A80001)转换为结构指针. 这两个函数失败时返回 NULL 且设置 h_ errno 错误变量,调用 h_strerror()可以得到详细的 字符串的 IP 和 32位的 IP 转换. 在网络上面我们用的 IP 都是数字加点(192.168.0.1)构成的, 而在 struct in_addr结构中 用的是 32 位的 IP , 我们上面那个 32 位 IP (C0A80001)是的 192.168.0.1 为了转换我们可以 使用下面两个函数 int inet_aton(const char *cp,struct in_addr *inp) char *inet_ntoa(struct in_addr in) 函数里面 a 代表 ascii n 代表 network.第一个函数表示将 a.b.c.d 的 IP 转换为 32 位的 I P,存储在 inp 指针里面.第二个是将 32 位 IP 转换为 a.b.c.d 的格式 服务信息函数 在网络程序里面我们有时候需要知道端口. IP 和服务信息.这个时候我们可以使用以下几 int getsockname( int sockfd,struct sockaddr *localaddr, int *addrlen) int getpeername( int sockfd,struct sockaddr *peeraddr, int *addrlen) struct servent *getservbyname(const char *servname,const char *protoname) struct servent *getservbyport( int port,const char *protoname) struct servent char *s_name; /* 正式服务名 */ char **s_aliases; /* 别名列表 */ int s_port; /* 端口号 */ char *s_proto; /* 使用的协议 */ 一般我们很少用这几个函数.对应客户端,当我们要得到连接的端口号时在 connect调用成 功后使用可得到 系统分配的端口号.对于服务端,我们用 INADDR_ANY 填充后,为了得到连 接的 IP 我们可以在 accept 调用成功后 使用而得到 IP 地址. 在网络上有许多的默认端口和服务,比如端口 21 对 ftp80 对应 WWW.为了得到指定的端口号 的服务 我们可以调用第四个函数,相反为了得到端口号可以调用第三个函数.
C++中Socket 网络编程 实例详解 现在几乎所有C/C++的后台程序都需要进行网络通讯,其实现方法无非有两种:使用系统底层socket或者使用已有的封装好的网络库。本文对两种方式进行总结,并介绍一个轻量级的网络通讯库ZeroMQ。  1.基本的Scoket编程 关于基本的scoket编程网络上已有很多资料,作者在这里引用一篇文章中的内容进行简要说明。 基于socket编程,基本上就是以下6个步骤: 1、socket()函数 2、bind()函数 3、listen()、connect()函数 4、accept()函数 5、read()、write()函数等 6、close()函数
Linux 错误码65280对应的错误号( errno )是126,表示执行一个命令时发生了错误。以下是常见的 Linux 错误号及其对应的错误: 1. EPERM (1):操作不允许 2. ENOENT (2):文件或目录不存在 3. ESRCH (3):没有这样的进程 4. E INT R (4):系统调用被中断 5. EIO (5):输入/输出错误 6. ENXIO (6):没有这样的设备或地址 7. E2BIG (7):参数列表太长 8. ENOEXEC (8):执行格式错误 9. EBADF (9):文件描述符无效 10. ECHILD (10):没有这样的子进程 11. EAGAIN (11):资源暂时不可用 12. ENOMEM (12):内存不足 13. EACCES (13):权限不足 14. EFAULT (14):错误的地址 15. ENOTBLK (15):块设备必须使用块IO 16. EBUSY (16):设备或资源忙 17. EEXIST (17):文件已存在 18. EXDEV (18):跨文件系统链接 19. ENODEV (19):操作不支持设备 20. ENOTDIR (20):不是目录 21. EISDIR (21):是目录 22. EINVAL (22):无效的参数 23. ENFILE (23):文件打开太多 24. EMFILE (24):文件描述符打开太多 25. ENOTTY (25):不是终端设备 26. ETXTBSY (26):文本文件忙 27. EFBIG (27):文件太大 28. ENOSPC (28):没有空间 29. ESP IP E (29):无效的seek 30. EROFS (30):只读文件系统 31. EMLINK (31):链接太多 32. EP IP E (32):捕获信号管道 33. EDOM (33):数学参数超出定义域 34. ERANGE (34):数学结果不可表示 35. EDEADLK (35):资源死锁避免 36. ENAMETOOLONG (36):文件名太长 37. ENOLCK (37):没有可用的记录锁 38. ENOSYS (38):函数不支持 39. ENOTEMPTY (39):目录不为空 40. ELOOP (40):太多的符号链接 41. ENOMSG (42):没有消息的标识符 42. EIDRM (43):标识符已删除 43. ECHRNG (44):通道范围不正确 44. EL2NSYNC (45):Level 2不同步 45. EL3HLT (46):Level 3被挂起 46. EL3RST (47):Level 3重置 47. ELNRNG (48):Link number超出范围 48. EUNATCH (49):Protocol driver不可用 49. ENOCSI (50):没有CSI结构可用 50. EL2HLT (51):Level 2被挂起 51. EBADE (52):无效的交换 52. EBADR (53):无效的请求描述符 53. EXFULL (54):交换空间已满 54. ENOANO (55):没有对应的自动识别对象 55. EBADRQC (56):无效的请求描述符或参数 56. EBADSLT (57):Slot不存在 57. EBFONT (59):无效字体文件格式 58. ENOSTR (60):设备不是流 59. ENODATA (61):没有数据可用 60. ETIME (62):计时器已过期 61. ENOSR (63):没有记录可用 62. ENONET (64):网络不可用 63. ENOPKG (65):包没有安装 64. EREMOTE (66):对象是远程的 65. ENOLINK (67):链路不存在 66. EADV (68):广告错误 67. ESRMNT (69):Srmount错误 68. ECOMM (70):通信错误 69. EPROTO (71):协议错误 70. EMULTIHOP (72):多跳跃I / O 71. EDOTDOT (73):RFS特定错误 72. EBADMSG (74):错误的消息 73. EOVERFLOW (75):值太大以便于定义 74. ENOTUNIQ (76):名称不唯一 75. EBADFD (77):文件描述符在错误状态 76. EREMCHG (78):远程地址已更改 77. ELIBACC (79):无法访问共享库 78. ELIBBAD (80):共享库损坏 79. ELIBSCN (81):没有共享库文本段 80. ELIBMAX (82):共享库表已满 81. ELIBEXEC (83):无法执行共享库 82. EILSEQ (84):无效的或不完整的多字节序列 83. ERESTART (85):无需重新启动系统调用 84. ESTRP IP E (86):管道流不支持 85. EUSERS (87):太多用户 86. ENOTSOCK (88):套接字操作的目标不是套接字 87. EDESTADDRREQ (89):需要目标地址 88. EMSGSIZE (90):消息太长 89. EPROTOTYPE (91):错误的协议类型 90. ENOPROTOOPT (92):协议不可用 91. EPROTONOSUPPORT (93):协议不支持 92. ESOCKTNOSUPPORT (94):套接字类型不支持 93. EOPNOTSUPP (95):操作不支持 94. EPFNOSUPPORT (96):协议族不支持 95. EAFNOSUPPORT (97):地址族不支持 96. EADDRINUSE (98):地址已在使用中 97. EADDRNOTAVAIL (99):不能分配所需的地址 98. ENETDOWN (100):网络已关闭 99. ENETUNREACH (101):网络不可达 100. ENETRESET (102):网络连接已重置 101. ECONNABORTED (103):连接被中止 102. ECONNRESET (104):连接被重置 103. ENOBUFS (105):没有缓冲区可用 104. EISCONN (106):套接字已连接 105. ENOTCONN (107):套接字未连接 106. ESHUTDOWN (108):不能执行发送,套接字已关闭 107. ETOOMANYREFS (109):太多参考:无法分配请求的资源 108. ETIMEDOUT (110):连接超时 109. ECONNREFUSED (111):连接被拒绝 110. EHOSTDOWN (112):主机已关闭 111. EHOSTUNREACH (113):主机不可达 112. EALREADY (114):操作已经在进行中 113. EINPROGRESS (115):操作正在进行中 114. ESTALE (116):Stale NFS文件句柄 115. EUCLEAN (117):结构取消 116. ENOTNAM (118):不是XENIX命名文件 117. ENAVAIL (119):No XENIX semaphores available 118. EISNAM (120):Is a named type file 119. EREMOTEIO (121):远程I / O错误 120. EDQUOT (122):Quota exceeded 121. ENOMEDIUM (123):没有中介信息 122. EMEDIUMTYPE (124):中介错误 123. ECANCELED (125):操作被取消 124. ENOKEY (126):没有KEY值 125. EKEYEXPIRED (127):KEY已过期 126. EKEYREVOKED (128):KEY已被撤销 127. EKEYREJECTED (129):KEY被拒绝 128. EOWNERDEAD (130):所有者已死 129. ENOTRECOVERABLE (131):无法恢复