(WinAPI) select() für dumme



  • Kann mir eine in einfachen worten die einzelnen parameter von select erklären und wie das eingesetzt wird, also was das mit diesem fd_set aufsich hat und so. und vielleich noch ein (nich allzu großen) beispiel code.
    Ich hab mir bestimmt schon 5 unterschiedliche beschreibungen angesehen und nichts davon kapiert(doch: der letzt parameter ist für timeout zuständig)



  • Das muss nach Linux, select() gibts in Standard C++ nicht.

    Der erste Parameter entspricht dem Wert des Höchsten Descriptors (Handles) + 1. Der zweite Parameter gibt ein Feld mit Handeln an, die zum Lesen zuständig sind. Der dritte ein Feld mit Handeln zum Schreiben, vierte für Fehlermeldungen, fünfter für Timeout.

    Angenommen, du definierst STDIN als 0 und hast ein Feld fd_set lesen. Du möchtest gerne benachrichtigt werden, wenn von STDIN gelesen werden kann. Dann musst du zuerst das Feld lesen in einen Zustand versetzen, in dem es Descriptors aufnehmen kann. Das machst du mit dem Makro FD_ZERO():

    FD_ZERO(&lesen);

    Dann fügst du STDIN zu lesen hinzu:
    FDSET(STDIN, &lesen);

    Nun kannst du schon select() aufrufen:

    select(STDIN + 1, lesen, NULL, NULL, NULL);
    if (FD_ISSET(STDIN, &lesen))
     printf("es wurde von stdin gelesen!\n");
    

    Du musst im Hinterkopf behalten, daß select() die Felder verändert. D.h., wird von STDIN nicht gelesen, sondern von einem anderen Handle, das jetzt nicht weiter von Interesse ist, wird STDIN aus dem Feld (fd_set) entfernt und der Ausdruck FD_ISSET(STDIN, &lesen) ist 0.
    select() wird häufig bei Serverapplikationen angewendet die nicht auf fork() basieren, um Clientanfragen parallel zu bearbeiten. Die Client-Sockets sind dann alle in einem fd_set drin und so kann immer schön abgefragt werden, wo und ob gerade Daten kommen.



  • Original erstellt von Doktor Prokt:
    **Das muss nach Linux, select() gibts in Standard C++ nicht.
    **

    jup
    Thread verschoben ins Unix Forum.



  • Warum klappt das nich:

    anfang des codes:

    #include <winsock.h>
    #include <stdio.h>
    #include <conio.h>
    
    #define MAXCLIENTS 10
    #define BUFFERSIZE 1024
    
    struct user{
        char name[50];
        int socket;
        user *prev;
        user *next;
    };
    
    user server;
    
    int user_nr=0;
    char buffer[BUFFERSIZE];
    

    und die funktion mit select:

    int interchange(void)
    {
        fd_set fds;
        FD_ZERO(&fds);
    
        struct timeval tv;
        tv.tv_sec=5;
        tv.tv_usec=0;
    
        user *p=&server;
        while(p->next!=NULL);
        {
            p=p->next;
            FD_SET(p->socket,&fds);
            select(MAXCLIENTS+1,&fds,NULL,NULL,&tv);
            recv(p->socket,buffer,sizeof(BUFFERSIZE)-1,0);
            if(FD_ISSET(p->socket,&fds))
            {
                printf("\ngelesen\n");
            }else printf("\n timeout\n");
        }
    return 0;
    }
    

    Er bleibt immer beim recv hängen.
    PS. lasst euch von dem ganzen drum herrum nich verwirren.

    [ Dieser Beitrag wurde am 03.11.2002 um 20:14 Uhr von TheDeath editiert. ]



  • Ist doch klar, daß er hängen bleibt:

    recv() wartet so lange, bis es was received.
    recv() darf erst NACH der Abfrage if(FD_ISSET(...)) aufgerufen werden. Dann funktioniert es. Es muss also im if-Block stehen.



  • So? geht immer noch nich, bleibt nach dem aufruf der schleife hänge, also er gibt auf dem monitor "schleife beginnt" aus und macht dann nix mehr.

    int interchange(void)
    {
        fd_set fds;
        FD_ZERO(&fds);
    
        struct timeval tv;
        tv.tv_sec=5;
        tv.tv_usec=0;
    
        user *p=&server;
    
        printf("schleife beginnt\n");
    
        while(p->next!=NULL);
        {
            p=p->next;
            FD_SET(p->socket,&fds);
    
            select(MAXCLIENTS+1,&fds,NULL,NULL,&tv);
    
            printf("select ok");
    
            if(FD_ISSET(p->socket,&fds))
            {
                recv(p->socket,buffer,sizeof(BUFFERSIZE)-1,0);
    
                printf("\ngelesen\n");
            }else printf("\n timeout\n");
        }
    return 0;
    }
    


  • Hm, jo, select() darfst du natürlich nur einmal aufrufen.

    Versuchs mal so:

    int interchange(void)
    {
        int i;
        fd_set fds;
        FD_ZERO(&fds);
    
        struct timeval tv;
        tv.tv_sec=5;
        tv.tv_usec=0;
    
        user *p=&server;
    
        printf("schleife beginnt\n");
    
        while(p->next!=NULL);
        {
            p=p->next;
            FD_SET(p->socket,&fds);
        }
    
            select(MAXCLIENTS+1,&fds,NULL,NULL,&tv);
    
            printf("select ok");
         for (i = 0; i <= MAXCLIENTS; i++)
         {
    
            if(FD_ISSET(i,&fds))
            {
                recv(i,buffer,sizeof(BUFFERSIZE)-1,0);
    
                printf("\ngelesen\n");
            }
         }
    return 0;
    }
    

    So sollte es funktionieren.



  • klappt immer noch nich, der mag das select nich, die schleife startet er ganz normal nur kommt dann KEINE meldung das select ausgeführt wurde.
    achja, das programm soll für windows sein, kann es sein das die funktion da nich funktioniert?



  • Hm, keine Ahnung, wusste bis gestern gar nicht, daß es select() auch für Windows gibt. Auf jeden Fall sollte er "select ok" spätestens nach deiner vereinbarten TimeOut-Zeit ausführen. Das einzige, was ich mir noch vorstellen kann, ist, daß du vor dem Aufruf der Funktion interchange() eine andere Funktion aufrufst, die das Programm blockiert und auf irgendwas wartet. Oder es kann sein, daß die Liste falsch implmentiert ist und er keinen Pointer mit dem Wert NULL findet...
    Poste einfach mal mehr Code, dann finden mer das schon raus.



  • **
    achja, das programm soll für windows sein, kann es sein das die funktion da nich funktioniert?
    **
    Vieles funktioniert unter Windows nicht... aber "select" sollte schon gehen 😃

    Was für ein Return-Wert kriegst du eigentlich von select?
    Ohne errno oder return-Wert weist du nicht ob das geklappt hat...



  • Ich pack das mal in das WinAPI Forum, wenn es um Windos geht, da die WinAPI Socket Unterstützung doch sehr simpel und primitiv ist im Gegensatz zu den POSIX Sockets und du sicher mit anderen Problemen kämpfen musst.

    hier sind ein paar Links, die dir sicher helfen (sind aber für Unix)

    http://www.acme.com/software/thttpd/ <-- Beispiel Programm

    @Doktor
    select muss man doch eigentlich in die Schleife packen! Wie soll select sonst die Bitmaske setzen?

    [ Dieser Beitrag wurde am 04.11.2002 um 20:31 Uhr von kingruedi editiert. ]


Anmelden zum Antworten