Pregunta

Una función que a menudo se pasa por alto y que no requiere biblioteca externa, pero que básicamente no tiene documentación alguna.

¿Fue útil?

Solución

ACTUALIZACIÓN (2010-10-11):Las páginas de manual de Linux ahora tienen documentación de getaddrinfo_a, puede encontrarla aquí: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo_a.3.html

Como descargo de responsabilidad, debo agregar que soy bastante nuevo en C, pero no exactamente un novato, por lo que puede haber errores o malas prácticas de codificación, corríjame (y mi gramática también apesta).

Yo personalmente no lo sabía hasta que encontré esta publicación por Adam Langley, daré algunos fragmentos de código para ilustrar su uso y aclarar algunas cosas que podrían no quedar tan claras en el primer uso.Los beneficios de usar esto es que obtiene datos fácilmente utilizables en enchufe(), escuchar() y otras funciones, y si se hace bien, tampoco tendrás que preocuparte por ipv4/v6.
Entonces, para comenzar con lo básico, según lo tomado del enlace anterior (deberá vincularse con libanl (-lanl)):
Aquí está el prototipo de función:

int getaddrinfo_a(int mode, struct gaicb *list[], int ent, 
                  struct sigevent *);
  1. El modo es GAI_WAIT (que probablemente no sea lo que desea) y GAI_NOWAIT para búsquedas asíncronas
  2. El gaicb El argumento acepta una serie de hosts para buscar con el ent argumento que especifica cuántos elementos tiene la matriz
  3. El sigevento será responsable de decirle a la función cómo debemos ser notificados, más sobre esto en un momento

Una estructura gaicb se ve así:

struct gaicb {
    const char *ar_name;
    const char *ar_service;
    const struct addrinfo *ar_request;
    struct addrinfo *ar_result;
};

Si está familiarizado con getaddrinfo, estos campos corresponden a ellos así:

int getaddrinfo(const char *node, const char *service,
                const struct addrinfo *hints,
                struct addrinfo **res);

El nodo es el campo ar_name, el servicio es el puerto, el argumento de sugerencias corresponde al miembro ar_request y el resultado se almacena en el resto.
Ahora especificas cómo quieres que te notifiquen a través de la estructura sigevent:

struct sigevent {
    sigval_t sigev_value;
    int sigev_signo;
    int sigev_notify;
    void (*sigev_notify_function) (sigval_t);
    pthread_addr_t *sigev_notify_attributes;
};
  1. Puede ignorar la notificación configurando _sigev_notify_ en SIGEV_NONE
  2. Puede activar una señal configurando sigev_notify en SIGEV_SIGNAL y sigev_signo en la señal deseada.Tenga en cuenta que cuando utilice una señal en tiempo real (SIGRTMIN-SIGRTMAX, úselo siempre a través de las macros y la adición SIGRTMIN+2, etc.) puede pasar un puntero o valor en el miembro sigev_value.sival_ptr o sigev_value.sival_int respectivamente
  3. Puede solicitar una devolución de llamada en un hilo nuevo configurando sigev_notify en SIGEV_NONE

Básicamente, si desea buscar un nombre de host, establezca ar_name en el host y configure todo lo demás en NULO, si desea conectarse a un host, configure ar_name y ar_service, y si desea crear un servidor, especifique ar_service y el campo ar_result.Por supuesto, puedes personalizar el miembro ar_request a tu gusto, mira hombre getaddrinfo para más información.

Si tiene un bucle de eventos con select/poll/epoll/kqueue, es posible que desee utilizar señalfd por conveniencia.Signalfd crea un descriptor de archivo en el que puede utilizar los mecanismos habituales de sondeo de eventos como este:

#define _GNU_SOURCE //yes this will not be so standardish
#include <netdb.h>
#include <signal.h>
#include <sys/signalfd.h>

void signalfd_setup(void) {
    int sfd;
    sigset_t mask;

    sigemptyset(&mask);
    sigaddset(&mask, SIGRTMIN);
    sigprocmask(SIG_BLOCK, &mask, NULL); //we block the signal
    sfd = signalfd(-1, &mask, 0);
    //add it to the event queue
}
void signalfd_read(int fd) {
    ssize_t s;
    struct signalfd_siginfo fdsi;
    struct gaicb *host;

    while((s = read(fd, &fdsi, sizeof(struct signalfd_siginfo))) > 0){
    if (s != sizeof(struct signalfd_siginfo)) return; //thats bad
    host = fdsi.ssi_ptr; //the pointer passed to the sigevent structure
            //the result is in the host->ar_result member
            create_server(host);
    }
}
void create_server(struct gaicb *host) {
    struct addrinfo *rp, *result;
    int fd;

    result = host->ar_result;
    for(rp = result; rp != NULL; rp = rp->ai_next) {
        fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        bind(fd, rp->ai_addr, rp->ai_addrlen);
        listen(fd, SOMAXCONN);
        //error checks are missing!

        freeaddrinfo(host->ar_request);
        freeaddrinfo(result);
        //you should free everything you put into the gaicb
    }
}
int main(int argc, char *argv[]) {
    struct gaicb *host;
    struct addrinfo *hints;
    struct sigevent sig;

    host = calloc(1, sizeof(struct gaicb));
    hints = calloc(1, sizeof(struct addrinfo));

    hints->ai_family = AF_UNSPEC; //we dont care if its v4 or v6
    hints->ai_socktype = SOCK_STREAM;
    hints->ai_flags = AI_PASSIVE;
    //every other field is NULL-d by calloc

    host->ar_service = "8888"; //the port we will listen on
    host->ar_request = hints;

    sig.sigev_notify = SIGEV_SIGNAL;
    sig.sigev_value.sival_ptr = host;
    sig.sigev_signo = SIGRTMIN;

    getaddrinfo_a(GAI_NOWAIT, &host, 1, &sig);

    signalfd_setup();

    //start your event loop
    return 0;
}

Por supuesto, también puedes usar un manejador de señales simple para este trabajo, mira hombre sigaction para más información.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top