侧边栏壁纸
博主头像
noerror

虚灵不寐,众理具而万事出。

  • 累计撰写 239 篇文章
  • 累计创建 9 个标签
  • 累计收到 2 条评论
标签搜索

目 录CONTENT

文章目录

getaddrinfo_a函数用法详解

noerror
2022-11-09 / 0 评论 / 0 点赞 / 24 阅读 / 2,414 字 / 正在检测是否收录...

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);
}
0

评论区