Frage

Eine übersehen Funktion oft, die keine externe Bibliothek erfordert, hat aber im Grunde keine whatsoever Dokumentation.

War es hilfreich?

Lösung

UPDATE (2010-10-11) : Der Linux-man-pages jetzt Dokumentation der getaddrinfo_a haben, können Sie es finden Sie hier: http://www.kernel.org/doc/man-pages/online/pages/man3/getaddrinfo_a .3.html

Als Haftungsausschluss sollte ich hinzufügen, dass ich zu C recht neu bin, aber nicht gerade ein Neuling, so könnte es Fehler oder schlechte Programmierpraktiken sein, bitte ich Sie korrigieren (und meine Grammatik saugt auch).

ich persönlich nicht darüber wusste, bis ich kam auf dieser Beitrag von Adam Langley, werde ich ein paar Code-Schnipsel gibt die Verwendung von illustrieren und einige Dinge klarstellen, die nicht so klar auf dem ersten Gebrauch sein könnten. Die Vorteile dieses zu verwenden, ist, dass Sie Daten leicht verwendbar zurück socket () listen () und andere Funktionen, und wenn es richtig gemacht Sie müssen sich keine Sorgen über IPv4- / v6 entweder.
Also mit den Grundlagen beginnen, wie oben von der Verbindung genommen (Sie müssen gegen libanl verknüpfen (-lanl)):
Hier ist der Funktionsprototyp:

int getaddrinfo_a(int mode, struct gaicb *list[], int ent, 
                  struct sigevent *);
  1. Die Modus ist entweder GAI_WAIT (was wahrscheinlich nicht das, was Sie wollen) und GAI_NOWAIT für Asynchron-Lookups
  2. Die gaicb Argument ein Array von Hosts mit dem ent Argument angibt, wie viele Elemente das Array Nachschlag akzeptiert hat
  3. Die sigevent wird für das Erklären der Funktion verantwortlich sein, wie wir benachrichtigt werden, mehr dazu in einem Moment

Ein gaicb Struktur sieht wie folgt aus:

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

Wenn Sie mit getaddrinfo vertraut sind, dann werden diese Felder, um sie entsprechen in etwa so:

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

Der Knoten ist der ar_name Bereich, Service die Port ist, entspricht die Hinweise Argument des ar_request Element und das Ergebnis wird in dem Rest gespeichert.
Jetzt bestimmen Sie, wie Sie durch die sigevent Struktur benachrichtigt werden möchten:

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. Sie können die Meldung ignorieren über die Einstellung _sigev_notify_ zu SIGEV_NONE
  2. Sie können ein Signal auslösen über die Einstellung sigev_notify zu SIGEV_SIGNAL und sigev_signo auf das gewünschte Signal. Beachten Sie, dass, wenn ein Echtzeitsignal mit ( SIGRTMIN - SIGRTMAX , verwenden Sie es immer über die Makros und zusätzlich SIGRTMIN +2 usw.) Sie entlang eines Zeigers oder Wert im sigev_value.sival_ptr oder sigev_value.sival_int Mitglied respectivley passieren kann
  3. Sie können einen Rückruf in einem neuen Thread anfordern über die Einstellung sigev_notify zu SIGEV_NONE

Also im Grunde, wenn Sie einen Hostnamen suchen Sie ar_name an den Host und setzen alles andere NULL gesetzt ist, wenn Sie wollen einen Host Sie ar_name und ar_service gesetzt, und wenn Sie eine Verbindung herstellen will einen Server erstellen Sie ar_service und das ar_result Feld angeben. Sie können natürlich anpassen, um das ar_request Mitglied zu Ihrem Herzinhalt, Blick auf man getaddrinfo für weitere Informationen.

Wenn Sie eine Ereignisschleife haben mit select / Umfrage / epoll / kqueue Sie vielleicht verwenden möchten signalfd für die Bequemlichkeit. Signalfd erstellt einen Dateideskriptor, auf dem die usuall Ereignisabfrage Mechanismen wie so verwenden können:

#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;
}

Sie können natürlich auch einen einfachen Signal-Handler für diesen Job verwenden, suchen Sie unter Mann sigaction für weitere Informationen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top