getaddrinfo_a函数用法详解
getaddrinfo_a函数简介
- 头文件包含
#include <netdb.h>
- 函数定义
int getaddrinfo_a(int mode , struct gaicb * list[] ,
int nitems , struct sigevent * sevp );
int gai_suspend(const struct gaicb * const list[] , int nitems ,
const struct timespec * timeout );
int gai_error(struct gaicb * req );
int gai_cancel(struct gaicb * req );
- 编译链接选项
-lanl
getaddrinfo_a函数常见使用错误
- 链接错误
undefined reference to `getaddrinfo_a'
解决办法:添加链接选项
-lanl
- 编译错误
warning: implicit declaration of function ‘getaddrinfo_a’ [-Wimplicit-function-declaration]
解决办法:包含头文件
#include <netdb.h>
getaddrinfo_a函数详细描述
getaddrinfo_a ()函数执行与getaddrinfo (3)相同的任务,但允许异步执行多个名称查找,并在查找操作完成时发出可选通知。
mode参数具有以下值之一:
- GAI_WAIT 同步执行查找。调用将阻塞,直到查找完成。
- GAI_NOWAIT 异步执行查找。调用立即返回,请求在后台得到解决。参见下面对sevp参数的讨论。
数组list指定要处理的查找请求。nitems参数指定并行启动请求的查找操作的list 中的元素数。list中的空元素被忽略。每个请求由gaicb结构描述,定义如下:
struct gaicb {
const char *ar_name;
const char *ar_service;
const struct addrinfo *ar_request;
struct addrinfo *ar_result;
};
该结构的元素对应于getaddrinfo (3)的参数,因此,ar_name对应于node参数,ar_service对应于service参数,标识互联网主机和服务。ar_request元素对应于hints参数,指定选择返回的套接字地址结构的标准。最后,ar_result对应于res参数;您不需要初始化此元素,它将在请求解析时自动设置。getaddrinfo (3)中描述了最后两个元素引用的addrinfo结构
当mode被指定为GAI_NOWAIT 时,可以通过使用sevp参数所指向的sigevent结构来获得关于已解析请求的通知。有关此结构的定义和一般详细信息,请参见sigevent (7).sevp->sigev_notify字段可以具有以下值:
- SIGEV_NONE不提供任何通知。
- SIGEV_SIGNAL查找完成后,为进程生成信号sigev_signo。有关一般详细信息,请参见sigevent (7)。siginfo_t结构的si_code字段将设置为SI_ASYNCNL
- SIGEV_THREAD当查找完成时,调用sigev_notify_function,就像它是新线程的启动函数一样。详见sigevent (7)。
对于SIGEV_SIGNAL和SIGEV_THREAD ,将sevp->sigev_valuesival_ptr指向list 可能是有用的
gai_suspend ()函数挂起调用线程的执行,等待数组list 中的一个或多个请求完成。nitems参数指定调用阻塞的数组list 的大小,直到发生以下情况之一:
- list中的一个或多个操作完成。
- 呼叫被捕获的信号中断。
- 已过timeout中指定的时间间隔。此参数指定以秒加纳秒为单位的超时(有关timespec结构的详细信息,请参见nanosleep (2))。如果timeout为空,则调用将无限期阻塞(直到上述事件之一发生)。
没有明确说明完成了哪项请求;您必须通过在请求列表上迭代gai_error ()来确定哪些请求已经完成。
gai_error ()函数返回请求req :的状态,如果请求尚未完成,则返回 EAI_INPROGRESS ,如果处理成功,则返回0,如果请求无法解析,则返回错误代码。
gai_cancel ()函数取消请求req 如果请求被成功取消,请求的错误状态将被设置为 EAI_CANCELED ,并将执行正常的异步通知。如果请求当前正在处理中,则不能取消该请求;在这种情况下,它将被处理为从未调用过gai_cancel ()。如果req为空,则尝试取消进程发出的所有未完成的请求。
getaddrinfo_a函数返回值
如果所有请求都已成功排队,则getaddrinfo_a ()函数返回0,或者返回以下非零错误代码之一:
- EAI_AGAIN 将查找请求排队所需的资源不可用。应用程序可以检查每个请求的错误状态,以确定哪些请求失败。
- EAI_MEMORY 内存不足。
- EAI_SYSTEM mode无效。
如果列出的请求中至少有一个已经完成,gai_suspend ()函数将返回0。否则,它将返回以下非零错误代码之一:
- EAI_AGAIN 在任何请求完成之前,给定的超时已过期。
- EAI_ALLDONE 没有向该函数发出实际请求。
- EAI_INTR 信号中断了功能。请注意,这种中断可能是由一些已完成的查找请求的信号通知引起的。
对于未完成的查找请求,gai_error ()函数可以返回 EAI_INPROGRESS ,对于成功完成的查找(如上所述),getaddrinfo (3)可以返回的错误代码之一,或者如果请求在完成之前被显式取消,则返回错误代码 EAI_CANCELED 。
gai_cancel ()函数可以返回以下值之一:
- EAI_CANCELED 请求已成功取消。
- EAI_NOTCANCELED 请求尚未取消。
- EAI_ALLDONE 请求已经完成。
gai_strerror (3)函数将这些错误代码转换为人类可读的字符串,适用于错误报告。
getaddrinfo_a函数其他说明
getaddrinfo_a ()的接口模仿lio_listio (3)接口。
getaddrinfo_a函数使用举例
提供了两个示例:一个简单的示例同步地并行解析多个请求,另一个复杂的示例显示了一些异步功能。Synchronous example下面的程序只是并行解析多个主机名,与使用getaddrinfo (3)顺序解析主机名相比,速度更快。该程序的使用方式如下:
$ \fB./a.out ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz\fP
ftp.us.kernel.org: 128.30.2.36
enoent.linuxfoundation.org: Name or service not known
gnu.cz: 87.236.197.13
这是程序源代码
#define _GNU_SOURCE
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int ret;
struct gaicb *reqs[argc \- 1];
char host[NI_MAXHOST];
struct addrinfo *res;
if (argc < 2) {
fprintf(stderr, "Usage: %s HOST...\en", argv[0]);
exit(EXIT_FAILURE);
}
for (int i = 0; i < argc \- 1; i++) {
reqs[i] = malloc(sizeof(*reqs[0]));
if (reqs[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
memset(reqs[i], 0, sizeof(*reqs[0]));
reqs[i]\->ar_name = argv[i + 1];
}
ret = getaddrinfo_a(GAI_WAIT, reqs, argc \- 1, NULL);
if (ret != 0) {
fprintf(stderr, "getaddrinfo_a() failed: %s\en",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
for (int i = 0; i < argc \- 1; i++) {
printf("%s: ", reqs[i]\->ar_name);
ret = gai_error(reqs[i]);
if (ret == 0) {
res = reqs[i]\->ar_result;
ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret != 0) {
fprintf(stderr, "getnameinfo() failed: %s\en",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
}
exit(EXIT_SUCCESS);
}
Asynchronous example这个例子展示了一个简单的交互式getaddrinfo_a ()前端。未演示通知功能。
示例会话可能如下所示:
$ \fB./a.out\fP
> a ftp.us.kernel.org enoent.linuxfoundation.org gnu.cz
> c 2
[2] gnu.cz: Request not canceled
> w 0 1
[00] ftp.us.kernel.org: Finished
> l
[00] ftp.us.kernel.org: 216.165.129.139
[01] enoent.linuxfoundation.org: Processing request in progress
[02] gnu.cz: 87.236.197.13
> l
[00] ftp.us.kernel.org: 216.165.129.139
[01] enoent.linuxfoundation.org: Name or service not known
[02] gnu.cz: 87.236.197.13
程序源如下:
#define _GNU_SOURCE
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static struct gaicb **reqs = NULL;
static int nreqs = 0;
static char *
getcmd(void)
{
static char buf[256];
fputs("> ", stdout); fflush(stdout);
if (fgets(buf, sizeof(buf), stdin) == NULL)
return NULL;
if (buf[strlen(buf) \- 1] == \(aq\en\(aq)
buf[strlen(buf) \- 1] = 0;
return buf;
}
/* Add requests for specified hostnames */
static void
add_requests(void)
{
int nreqs_base = nreqs;
char *host;
int ret;
while ((host = strtok(NULL, " "))) {
nreqs++;
reqs = realloc(reqs, sizeof(reqs[0]) * nreqs);
reqs[nreqs \- 1] = calloc(1, sizeof(*reqs[0]));
reqs[nreqs \- 1]\->ar_name = strdup(host);
}
/* Queue nreqs_base..nreqs requests. */
ret = getaddrinfo_a(GAI_NOWAIT, &reqs[nreqs_base],
nreqs \- nreqs_base, NULL);
if (ret) {
fprintf(stderr, "getaddrinfo_a() failed: %s\en",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
}
/* Wait until at least one of specified requests completes */
static void
wait_requests(void)
{
char *id;
int ret, n;
struct gaicb const **wait_reqs = calloc(nreqs, sizeof(*wait_reqs));
/* NULL elements are ignored by gai_suspend(). */
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >= nreqs) {
printf("Bad request number: %s\en", id);
return;
}
wait_reqs[n] = reqs[n];
}
ret = gai_suspend(wait_reqs, nreqs, NULL);
if (ret) {
printf("gai_suspend(): %s\en", gai_strerror(ret));
return;
}
for (int i = 0; i < nreqs; i++) {
if (wait_reqs[i] == NULL)
continue;
ret = gai_error(reqs[i]);
if (ret == EAI_INPROGRESS)
continue;
printf("[%02d] %s: %s\en", i, reqs[i]\->ar_name,
ret == 0 ? "Finished" : gai_strerror(ret));
}
}
/* Cancel specified requests */
static void
cancel_requests(void)
{
char *id;
int ret, n;
while ((id = strtok(NULL, " ")) != NULL) {
n = atoi(id);
if (n >= nreqs) {
printf("Bad request number: %s\en", id);
return;
}
ret = gai_cancel(reqs[n]);
printf("[%s] %s: %s\en", id, reqs[atoi(id)]\->ar_name,
gai_strerror(ret));
}
}
/* List all requests */
static void
list_requests(void)
{
int ret;
char host[NI_MAXHOST];
struct addrinfo *res;
for (int i = 0; i < nreqs; i++) {
printf("[%02d] %s: ", i, reqs[i]\->ar_name);
ret = gai_error(reqs[i]);
if (!ret) {
res = reqs[i]\->ar_result;
ret = getnameinfo(res\->ai_addr, res\->ai_addrlen,
host, sizeof(host),
NULL, 0, NI_NUMERICHOST);
if (ret) {
fprintf(stderr, "getnameinfo() failed: %s\en",
gai_strerror(ret));
exit(EXIT_FAILURE);
}
puts(host);
} else {
puts(gai_strerror(ret));
}
}
}
int
main(int argc, char *argv[])
{
char *cmdline;
char *cmd;
while ((cmdline = getcmd()) != NULL) {
cmd = strtok(cmdline, " ");
if (cmd == NULL) {
list_requests();
} else {
switch (cmd[0]) {
case \(aqa\(aq:
add_requests();
break;
case \(aqw\(aq:
wait_requests();
break;
case \(aqc\(aq:
cancel_requests();
break;
case \(aql\(aq:
list_requests();
break;
default:
fprintf(stderr, "Bad command: %c\en", cmd[0]);
break;
}
}
}
exit(EXIT_SUCCESS);
}
评论区