mehrere winsock recv gleichzeitig abhandeln?



  • unter windows ist select aber die aller langsamste methode



  • @thepro:
    danke für deine antwort, habe - würd ich sagen - realtiv gute grundkentnisse in c++ ansich, winapi ist ziemlich neu für mich.
    so hab ich das mit select noch garnicht gesehen, das wäre dann ja eig ne ziemlich
    gute lösung für mein problem.
    jetzt weiß ich wenigstens auf welchen dampfer ich muss 🙂 - danke dir.

    hustbaer schrieb:

    ThePro schrieb:

    Die Profis machen das wohl überwiegend mit select.

    Nein.

    Wenn du eine Aussage schon definitiv verneinst, dann würde mich interessieren
    was du denn dann für richtig hältst.

    Wäre dieser Ablauf so einigermaßen korrekt,
    oder habe ich etwas wichtiges vergessen?

    `

    Thread 1:

    Schleife starten

    __Prüfen ob eine Verbindung am ListenSocket vorliegt

    ____Wenn Ja: ins SET eintragen (Mutex)

    Schleife beenden

    Thread 2:

    Schleife starten

    __Prüfen ob Daten an einem SET-Eintrag anliegen (Mutex)

    ____Wenn Ja: Daten empfangen

    Schleife beenden

    `

    Danke an alle, Doll



  • Der erste Thread ist überflüssig.
    Die Verbindungen kannst du im selben Thread annehmen, in dem du auch die Daten empfängst.

    Hier siehst du wie es Beispielhaft gelöst wurde:
    http://www.c-worker.ch/tuts/select.php#server

    Nachschauen, ob eine neue Verbindung angenommen werden kann.

    // acceptSocket is im fd_set? => verbindung annehmen (sofern es platz hat)
        if(FD_ISSET(acceptSocket,&fdSet)) {
          // einen freien platz für den neuen client suchen, und die verbingung annehmen
          for(i=0;i<MAX_CLIENTS;i++)
          {
            if(clients[i]==INVALID_SOCKET)
            {
              clients[i]=accept(acceptSocket,NULL,NULL);
              printf("Neuen Client angenommen (%d)\n",i);
              break;
            }
          }
        }
    

    Nachschauen ob Daten empfangen werden können

    // prüfen wleche client sockets im fd_set sind
        for(i=0;i<MAX_CLIENTS;i++)
        {
          if(clients[i]==INVALID_SOCKET)
          {
            continue; // ungültiger socket, d.h. kein verbunder client an dieser position im array
          }
          if(FD_ISSET(clients[i],&fdSet))
          {
            rc=recv(clients[i],buf,256,0);
            // prüfen ob die verbindung geschlossen wurde oder ein fehler auftrat
            if(rc==0 || rc==SOCKET_ERROR)
            {
              printf("Client %d hat die Verbindung geschlossen\n",i);
              closesocket(clients[i]); // socket schliessen         
              clients[i]=INVALID_SOCKET; // seinen platz wieder freigeben
            }
            else
            {
              buf[rc]='\0';
              // daten ausgeben und eine antwort senden
              printf("Client %d hat folgendes gesandt: %s\n",i,buf);
              // antwort senden
              sprintf(buf2,"Du mich auch %s\n",buf);
              send(clients[i],buf2,(int)strlen(buf2),0);
            }
          }
        }
    


  • doll schrieb:

    hustbaer schrieb:

    ThePro schrieb:

    Die Profis machen das wohl überwiegend mit select.

    Nein.

    Wenn du eine Aussage schon definitiv verneinst, dann würde mich interessieren
    was du denn dann für richtig hältst.

    Man verwendet üblicherweise andere de-multiplexer, wie z.B. IO Completion Ports, epoll oder kqueue.



  • hustbaer schrieb:

    doll schrieb:

    hustbaer schrieb:

    ThePro schrieb:

    Die Profis machen das wohl überwiegend mit select.

    Nein.

    Wenn du eine Aussage schon definitiv verneinst, dann würde mich interessieren
    was du denn dann für richtig hältst.

    Man verwendet üblicherweise andere de-multiplexer, wie z.B. IO Completion Ports, epoll oder kqueue.

    Gibt es diese Funktionen unter Windows überhaupt?



  • ThePro schrieb:

    Der erste Thread ist überflüssig.
    Die Verbindungen kannst du im selben Thread annehmen, in dem du auch die Daten empfängst.

    Okay, angenommen folgendes ergibt sich:

    Eine Verbindung wurde in das Set eingetragen und mit select wird
    gerade (wie in dem Beispiel) darauf gewartet dass dieser wieder lesbar wird.

    In der gleichen Zeit will der Benutzer eine neue Verbindung aufbauen.

    Dann hängt das Programm doch immer noch bei Select (solang ich keinen Timeout setze - was ja bei C-Worker auch nicht der Fall ist), und kann die neue Verbindung nicht aufbauen solange der 'alte' Socket nicht noch einmal lesbar wurde (weil der neue ja noch garnicht eingetragen ist).

    also:
    - Socket1 wird ins Set eingetragen
    - Mit Select wird darauf gewartet dass Daten am Socket1 kommen
    - Es kommen Daten am Socket1
    - Keine neuen Verbindungen, also wieder zu Select (blockiert, bis Socket1 lesbar, da ja nur Socket1 bisher im Set)
    - Jetzt versucht der Benutzer eine neue Verb. aufzubauen

    -> klappt erst, sobald select nicht mehr blockiert,
    --> und das blockiert erst nicht mehr wenn etwas am Socket1 kommt



  • Gibt es diese Funktionen unter Windows überhaupt?

    Welche?



  • Du kannst einem der drei Sets einen 'Fake'-Socket hinzufügen.
    Wenn du diesen aus einem anderen Thread mit closesocket schließt kehrt select zurück.

    Klingt zwar unsauber, aber anders wird es wohl nicht gehen.



  • MrNoname schrieb:

    hustbaer schrieb:

    doll schrieb:

    hustbaer schrieb:

    ThePro schrieb:

    Die Profis machen das wohl überwiegend mit select.

    Nein.

    Wenn du eine Aussage schon definitiv verneinst, dann würde mich interessieren
    was du denn dann für richtig hältst.

    Man verwendet üblicherweise andere de-multiplexer, wie z.B. IO Completion Ports, epoll oder kqueue.

    Gibt es diese Funktionen unter Windows überhaupt?

    IO Completion Ports ja, die anderen nein. Ich habe auch nicht behauptet dass diese Interfaces "portabel" wären. Man kann allerdings Wrapper um diese de-multiplexer bauen, so dass man auf allen Systemen das selbe Wrapper-Interface verwenden kann.



  • doll schrieb:

    ThePro schrieb:

    Der erste Thread ist überflüssig.
    Die Verbindungen kannst du im selben Thread annehmen, in dem du auch die Daten empfängst.

    Okay, angenommen folgendes ergibt sich:

    Eine Verbindung wurde in das Set eingetragen und mit select wird
    gerade (wie in dem Beispiel) darauf gewartet dass dieser wieder lesbar wird.

    In der gleichen Zeit will der Benutzer eine neue Verbindung aufbauen.

    Dann hängt das Programm doch immer noch bei Select (solang ich keinen Timeout setze - was ja bei C-Worker auch nicht der Fall ist), und kann die neue Verbindung nicht aufbauen solange der 'alte' Socket nicht noch einmal lesbar wurde (weil der neue ja noch garnicht eingetragen ist).
    (...)

    Der "neue" ist noch nicht eingetragen, aber der Socket über den du Verbindungen annehmen möchtest, sollte eingetragen sein.
    D.h. in deinem Beispiel hast du 1x den "listen socket" und 1x den "socket for connection 1" im FD_SET.

    select() kommt dann zurück, sobald entweder der "socket for connection 1" lesbar/schreibbar wird, ODER eine neue Verbindung am "listen socket" eingeht.
    Lies dir die Doku zu select() durch, da sollte genau drin stehen, welche Bedingungen/Ereignisse für welches der drei Sets "gelten", so dass select() zurückkommt.

    p.S.: damit das gut funktioniert, sollte man den "listen socket" auch im non-blocking Modus betreiben (die "connection" Sockets sowieso). Sonst kann es einem passieren, dass listen() meldet es wäre eine Verbindung da, nur bis man accept() aufruft, ist die Gegenstelle futsch (antwortet nichtmehr oder hat schon ein RST geschickt). Dann würde accept() nämlich blockieren, und das wäre weniger gut. Im non-blocking Mode bekommt man in dem Fall von accept() einfach einen EWOULDBLOCK, und alles ist gut.



  • falls du "C++ von A bis Z" noch zur hand hast: darin wird (wenn ich mich noch recht erinnere) ausführlich auf select eingegangen und an einem tcp-client-server beispiel demonstriert...



  • hustbaer schrieb:

    select() kommt dann zurück, sobald entweder der "socket for connection 1" lesbar/schreibbar wird, ODER eine neue Verbindung am "listen socket" eingeht.

    super, jetzt macht das endlich sinn 😃



  • Ahh sorry ich hatte nur das "Jetzt versucht der Benutzer eine neue Verb. aufzubauen" gelesen und daraus geschlossen das du einen Client programmierst wo der Benutzer dynamisch Verbindungen herstellen kann.

    Für einen Server macht mein Vorschlag mit dem Fake-Socket dann keinen Sinn.



  • ------ schrieb:

    Ahh sorry ich hatte nur das "Jetzt versucht der Benutzer eine neue Verb. aufzubauen" gelesen und daraus geschlossen das du einen Client programmierst wo der Benutzer dynamisch Verbindungen herstellen kann.

    Für einen Server macht mein Vorschlag mit dem Fake-Socket dann keinen Sinn.

    danke trotzdem, für deine mühe! und aller anderen natürlich 😉


Anmelden zum Antworten