[C] select und fd_set

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • [C] select und fd_set

    Moin leute!

    Nun habe ich mich auch mal an C heran gewagt, soll ja performanter für Server-Aufgaben sein, habe ich gegehört

    Es geht um den Befehl select bzw. dass was Select nachdem es aufgeweckt wurde wieder zurück gibt.
    Es dabei verwende ich nur ein Read-Set. Auf sich Tutorialen sehe ich immer, dass man mittels ner While/For und "If" jeden Zeiger durchgehen muss und gucken ob dieser der Grund für select-wecken war. Wie sieht denn fd_set intern aus. - Wie kann ich mittels ner Schleife einfach alle in der von select neu übergebenen Set enthalten Werte rausholen?

    MfG
    20th

  • #2
    1. http://msdn.microsoft.com/library/de...k/fd_set_2.asp
    und
    2. http://msdn.microsoft.com/library/de...k/select_2.asp

    achte mal auf das hier:
    Four macros are defined in the header file Winsock2.h for manipulating and checking the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which can be modified by defining FD_SETSIZE to another value before including Winsock2.h.) Internally, socket handles in an fd_set structure are not represented as bit flags as in Berkeley Unix. Their data representation is opaque. Use of these macros will maintain software portability between different socket environments. The macros to manipulate and check fd_set contents are:

    FD_CLR(s, *set)
    Removes the descriptor s from set.
    FD_ISSET(s, *set)
    Nonzero if s is a member of the set. Otherwise, zero.
    FD_SET(s, *set)
    Adds descriptor s to set.
    FD_ZERO(*set)
    Initializes the set to the null set.
    BTW: wenn du was suchst, suche in der richtigen WebSite, alles was du für die Programmierung mit MS-Produkte brauchst, findest du in http://msdn.microsoft.com (wo denn sonst )

    Kommentar


    • #3
      Schonmal danke, aber dass du nun nicht ganz wissen konntest, was ich meinte, lag an meiner unartikulierten Niederschrift

      Die msdn kenne ich, aber ich weis nicht, inwie fern die von den Unix-Headern abweicht. Ok. StdIo etc werden gleich sein.

      Ok. Dann versuche ich es nochmal:
      select gibt mir ein neues Set zurück. Dort steht nicht mehr drin, auf welchen FDs er lauschen sollte sondern wo sich was geregt hat.
      Mein Frage, ist es nicht möglich, alle Zurückgegeben FDs direkt aus diesem Set/Variable zu holen. Die müssen ja auch irgendwo in Arrays dort gespeichert sein. Anstatt, und nun kommt der Clue ,
      Jede Verbindung die man sich gemekrt hat mit FD_ISSET abzufragen, wenn's zutrift weiter machen. Ich mein, 100 schleifendurch gänge sind kein Thema für den, aber mal erlich, das gelbe vom Ei isset () nicht...

      Kommentar


      • #4
        Ähm ... AFAIK der einzige Unterschied zwischen Window und Linux/Unix bei dieser Funktion ist, dass das 1. Argument in Window nur so sein Dasein pflegt und hat keinerlei Auswirkung auf das Ergebnis . Ist also nur wegen der Kompatibilität da.

        Tja, was willst du denn sonst machen, natürlich musst du in einer Schleife die Werte abklopfen. Was anderes macht z.B. eine Portforwarding Routine auch nicht, die ganze Überwachung steckt meist in einer Schleife derart for ( ; ; ) { ... }

        Kommentar


        • #5
          Nehmen wir mal an, ich habe 100 Connections. (Ist vielleicht dämlich für ein Prozess, sollte man eher forken) Aber es ist doch unsinnig diese 100 Dinger mit FD_ISSET(now_fd, &select_ret_addr) alle nach der reihe durch zu prüfen. Kann man nicht direkt auf $select_ret_addr zugreifen und sich die Verbindungen da heraus holen, wo sich was tut?

          Kommentar


          • #6
            nein, unsinnig ist deine Denkweise . Das Problem ist einfach. Du weisst nicht genau was sich da tut, du weisst nur dass es sich da was tut, falls der Returnwert != -1 ist. Also um es genau heraus zu bekommen, musst du alles per Schleife abklopfen, du kannst nicht einfach irgendwas bestimmtes ansprechen, da du nicht weisst ob dein Zielprozess auch aus der Liste ist. Bsp.: Terminaldienst eines Servers. Der Server kann nur durch überprüfen, ob

            - ein Client sich zu ihm verbindet und darauf reagiert
            - ein Client Aufgabe für ihn hat und fängt an zu rechnen
            - ...

            Der Server kann nicht drauf los gehen und:

            - einfach irgend ein Connection zu x-bliebigen Client aufbauen, die seiner Meinung nach sein Client sein müsste
            - einfach irgendwelche Ergebnisse von irgendwelcher Berechnung an einem Client seiner Wahl schicken, ohne eine Anforderung zu haben.
            - ...

            In diesem Fall muss man alle Werte mit FD_ISSET überprüfen und entweder neue Verbindung registrieren, oder bestehende Verbindung schliessen, oder eben angeforderte Dienste von bestehende Verbindungen servieren. Ich hoffe du verstehst was ich meine.

            Have a nice weekend.

            Kommentar


            • #7
              ARGL ^^ ich fühle mich irgendwie missverstanden


              Ok: Nochmal


              Das der server nicht einfach eine Verbindung zum clienten aufbauen kann ist klar auch das Andere alles.

              Ich hebe alle meine verbindungen, wie ich vorher mit accept() angenommen habe inne Liste auf. Ich weiß nicht, ob man das auch array nenen kann, aber müsste ein eindimensionales sein.

              Aus dieser Liste mit allen schon bereits Aufgebauten verbindungen erstelle ich ein Read FD-Set. Eine While rattert einfach alle Vorhanden Elemte in der Liste ab und fügt jede dem FD-Set mittels FD_SET hinzu. Nennen wir es read_fdset

              Wenn select() wieder aufwacht, ist es entweder weil ich einen Timeout eingebaut habe oder weil sich da auf irgendwelchen FDs irgendetwas getan hat. Sei's EOF/daten für die acceptierten conns , sei's ne neue Con für den lauschende FD. "read_fdset" enthält dann aber nicht mehr alle FDs die ich vorher alle mittels FD_SET in das set eingefügt habe, sondern nur noch die FDs auf denen sich etwas getan hat. Warum soll ich dann für alle Elemte die ich in meinem Array habe, mit dem ich das FD-Set erstelle, für jedes Element mit FD_ISSET überprüfen, ob dieses sich in dem Zurückgegeben FD-Set read_fdset von select oder sagen wir lieber "bearbeitetem" FD-Set befindet, wenn ich einfach nur alle FDs die in dem read_fdset enthalten sind durchackern müsste um diese zu Verarbeiten. Da ja das Macro FD_ISSET bloß deffiniert ist und nirgends der Source steht, kann ich nicht gucken, wie FD_SET auf das read_fdset zugreift. Ja, ich weiß nicht, was innerhalb des FD-Sets passiert, wenn du es genau wissen willst! - Sonst hätte ich nicht gefragt.
              Und bitte, erlzähle mir nicht, wie das Internet funzt - Ich weiß es

              Ich hoffe, des ist verständlich genug. - Ansonsten gebe ich es auf

              Kommentar


              • #8
                ich verstehe schon was du meinst, aber es geht nicht anders , weil:

                die 3 wichtigsten Argumente von select geben Information darüber was passiert. Sie sind vom Typ fd_set. fd_set ist eine Struktur aus 2 Teilen, der 1. gibt Auskunft über die Anzahl der zurückgegebenen Sockets an, der 2. Teil ist ein Array of SOCKET selbst. D.h. du kannst natürlich auf das Makro FD_ISSET verzichten und selbst das Array untersuchen.

                Nur, wie untersuchst du?

                Du musst ja gegen etwas prüfen, denn ohne Referenz kannst du nicht sagen, um wasfür ein SOCKET es sich handelt. Tja was machst du nun? Du hast keine andere Wahl als eine Schleife (jaja, da ist sie wieder ) zu nehmen, und durchläuft irgendwelche Referenzwerte und macht somit den Vergleich, jedoch manuell, d.h. wiederum dass du eine 2. innere Schleife brauchst, um das SOCKET-Array zu durchlaufen, was das Makro FD_ISSET ohnehin für dich schon tut, d.h. wiederum dass du besser FD_ISSET dafür nehmen soll, da deinen Code dadurch übersichtlicher wird. Die äussere Schleife bleibt. Fazit: wir sind wieder da, wo wir angefangen haben

                Na dann, wenn du einen anderen Weg findest, der funz, dann sag 's mir.

                Kommentar


                • #9
                  Das ich ohne Schleifen garnicht auskomme, war klar. ^^
                  Jedoch brauch ich den Socket bis auf dem socket_listenig nicht überprüfen. Es handelt sich um Eindirektionelle Verbindungen die bei einem Fehler einfach eine ID zurück geben und diese dann vom Master bearbeitet wird. Wenn ich wirklich auf dieses Socket schreiben muss, krame ich in dem Table herum wo ich die informationen für forked Childs ablege. Bitte Akzeptiere einfach, dass ich so eine Validierung nicht brauche und sage mir einfach, wenn du es weist, wie ich an die FDs komme. - Danke


                  fd_set:
                  PHP-Code:
                  typedef struct
                    
                  {
                      
                  __fd_mask __fds_bits[__FD_SETSIZE __NFDBITS];
                    } 
                  fd_set
                  Mehr steht nicht in der Header-File für das Struct drin. So also liegen da die FDs?


                  MfG
                  20th
                  Zuletzt geändert von 20thcentury; 07.08.2004, 13:10.

                  Kommentar


                  • #10
                    Original geschrieben von 20thcentury

                    fd_set:
                    PHP-Code:
                    typedef struct
                      
                    {
                        
                    __fd_mask __fds_bits[__FD_SETSIZE __NFDBITS];
                      } 
                    fd_set
                    nope, ich weisst nicht woher du diese Info hast, aber laut meiner Bücher ist fd_set sowohl in Windows als auch in Linux/Unix wie folgt definiert: (und damit arbeite ich auch)
                    PHP-Code:
                    typedef struct fd_set {
                      
                    u_int fd_count;
                      
                    SOCKET fd_array[FD_SETSIZE];
                    fd_set
                    Nun zurück zu deinem Problem. Irgendwie beisst du dich da fest an deiner Idee. Erkläre mir mal folgendes:

                    Du implementierst per FD_SET 'ne Menge Werte und übergibst sie an select zur Überwachung. Nun meldet select sich zurück mit einer Teilmenge von deiner Überwachungswerte. Wie zum Teufel willst du diese Teilmenge identifizieren, ohne mit deiner Liste zu Vergleichen und ohne die Liste der Teilmenge zu durchlaufen

                    Bsp. du bekommst ein array mit (1,2,3,6,8,9). Woher weisst du dass array[0] die 1 oder array[4] die 8 beinhaltet, ohne z.B. mit if (array[0]==1) ... zu prüfen? Natürlich kann du das array direkt ansprechen, aber ohne dessen Wert mit irgendwas zu vergleichen, ist eine Weiterbearbeitung nicht möglich, da du nicht weisst auf was du reagieren sollst.

                    Denk bitte nochmals drüber nach

                    Kommentar


                    • #11
                      Hey, so langsam nähern wir uns ja

                      Natürlich will ich das Array mit den FD-Sets durch whilen. - Das stand nie in Frage . Nur sehe ich dein Problem nicht . Select an sich ist ja ne Feine sache. Bloß, wenn ich mit FD_ISSET ja dann doch für jede Verbindung die ich MEINERSEITS in einem Array gespeichert habe prüfen muss, ob sich da irgendwas getan habe, sind da meinet wegen von 50 Durchläufen 48 umsonst, da sich da nichts regt.

                      Regt sich was auf dem Listen-Socket, also da, wo neue Conns rein kommen, so bekommt dies eine extra-Bearbeitung. Alle anderen Sockets sind zwangsweise Sockets, bei denen die Verbindung hergestellt wurde. - Sonst wären sie nicht in dem fd_set dan drin.

                      ich muss also nurnoch:


                      arr ist das FD-Array
                      PHP-Code:



                      while(tuhe_bis_ende)
                      {
                        
                      x++;

                        if(
                      arr[x] != listen_sock)
                        {
                          
                      read_len read(arr[x], buf1024);
                          
                      /* ....*/
                        
                      }
                        else
                        {
                          
                      reg_new_con(listen_sock);
                        }

                      Damit spaare ich mir jedoch, wenne ich bsp. 50 Connections habe, 50 Durchläufe und mache in der regel 2 oder 3. Verstanden? ^^

                      Ps: so gehts natürlich nicht )


                      Ich muss, wenn ich also die Verbunden Dinger abhöhren will nicht mehr wissen, wer mir was geschickt hat sondern ich will einfach nur noch die ergebnisse haben auf denen sich was getan hat. Wenn du mir nun immer noch nicht gläubig bist, vergiss es, ich werde es eh nicht mehr schaffen, es dir zu erklären - Ich wiederhol mich ja mittlerweile bloß dauerend.
                      Aber danke für die Struct-Deffinition.

                      Mfg
                      Zuletzt geändert von 20thcentury; 07.08.2004, 16:04.

                      Kommentar


                      • #12
                        Original geschrieben von 20thcentury

                        Aber danke für die Struct-Deffinition.
                        die habe ich dir aber bei meinem 1. Posting in dem 1. Link schon gegeben, da du aber wegen msdn nicht reingeschaut hast ... selbst schuld

                        es ist viel zu warm heute und ich muss noch ein paar Sachen zusammen packen, da wir morgen früh kurz mal ans Meer nach NL fahren, daher stop here, am Dienstag wieder.

                        Gruss

                        Kommentar


                        • #13
                          hmm, naut

                          vielleicht kann ich ja am Dienstag auch schon nen funzendes Code-Stück zeigen. Mom, läufts auch so, aber viel zu ressourcen schluckend

                          Was mir gerade aufgefallen ist, du hast nicht wirklich über 2500 Posts seit Februar 2004 gemacht?

                          Kommentar


                          • #14
                            Klar sind die Posts alle von mir seit 02/04 was soll die Frage

                            Nun zu deiner Posting vom 07-08-2004 16:57:

                            wer hindert dich daran nur das eine zuprüfen
                            etwa:
                            FD_ZERO(&deinSet);
                            FD_SET(deinWert,&deinSet);
                            ret = select(....);
                            if (....) { /* kein Fehler */
                            if FD_ISSET(deinWert, &deinSet) {
                            /* mach was du willst */
                            }
                            }
                            Wo ist das Problem

                            Kommentar


                            • #15
                              mich hindert dort niemanden dran....


                              nur ist "deinWert" ein Array mit mehren Einträgen. Können bald mehrere Hundert werden - und warum im Himmel soll ich dann diese 100 Einträge mit ner While durchackern, wenn ich einfach nur mit einer while die FDs ausdem fd_set dem Array heraus kriegen kann. Ich sage es nochmals: Mich interessiert nicht, was es für ein Fd ist, welche IP, welcher client etc. Es werden nur FDs in das fd_set reingepackt, welche auch sachen auf dem Socket abliefern dürfen. Bis auf das ich übrprüfe ob es sich gerade um das Haupt-socket handelt, muss ich nichts machen. außer auf das Abgelieferte Lauschen.
                              Nun nochmal plastisch dargestellt

                              Zuerst deine:
                              meineSockets ist ein array mit 100 FDs
                              PHP-Code:
                              while(bis ende meineSockets)
                              {
                               
                                if 
                              FD_ISSET(EinSocketaus-meineSockets, &deinSet
                                {
                                  
                              /* nehme Aufgabe an */
                                
                              {
                                else if(
                              Hauptsocket, &deinSet)
                                { 
                                  
                              /* Nehme neue verbindung an */
                                
                              }

                              Wenn ich also alles mit FD_ISSET überprüfen würde, müsste ich für jedes mal, wenn Select aufwacht 100 Durchgänge machen. Ist aber völlig überflüssig

                              Nun meine Methode:

                              deinSet ist das Set, was Select zurück gibt.
                              Sehe diese While als eine Art foreach in PHP
                              PHP-Code:
                              while(Ende von deinSet)
                              {
                                 if(
                              einEintrag-von-deinSet != Hauptsocket)
                                 {
                                    
                              read_len read(einEintrag-von-deinSetbuf1024);
                                    
                              /* Nehme aufgabe an */
                                 
                              else if(einEintrah-von-deinSet == Hauptsock)
                                 {
                                     
                              accept(einEintrag-von-deinSet);
                                  
                              /* Nehme neue verbindung an */
                                 
                              }

                              Ende vom Lied, das hier auch wirklich nur soviele Schleifendurchgänge gemacht wurden, wie nötig sind. Ich hoffe, es klickt

                              Kommentar

                              Lädt...
                              X