socket und terminal parallel lesen



  • Hi all!

    ich habe ein terminal programm was eine client verbindung zu einem server aufbaut. jetzt soll das programm eingaben auf dem terminal verarbeiten und gleichzeitig aber auch vom socket lesen können also wenn ich gerade was eingebe z.b. an der console und in dem moment kommt eine message über den socket rein wie kann das programm diese dann im hintergrund auswerten? weil ich hab das bis jetzt so verstanden das son terminal programm ja nacheinander abläuft und sich dann beendet. dies kann man ja nur durch schleifen verhindern aber wenn ich jetzt in einer schleife dauerhaft die console überwache wie kann dann der socket auch überwacht werden.ich hab da schon mal was über diese select() function gelesen und probiert, allerdings sehe ich da ned so richtig durch.

    ich hoffe ihr könnt mir helfen.

    Tschü



  • select bzw. pselect oder poll sind da wahrscheinlich die richtigen Ansätze. Ich hab schön länger nichts mehr mit sockets gemacht und weiss nicht ob mein Beispiel funktioniert. Hoffe aber, dass ich dir helfen kann, da man select und pselect am Anfang wirklich nur schwer versteht.

    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main(void)
    {
      struct timeval tv;
      fd_set fds;
      int s;
      int max;
    
      //öffne den Netzwerk Socket s  
    
      tv.tv_sec=/*wieviel sekunden soll select warten?*/0;
      tv.tv_usec=/*wieviel millisekunden soll select warten?*/0;
    
      max= s>0 ? s+1 : 1; /*größten descriptor + 1 bestimmen*/
    
      for(;;)
      {
        FD_ZERO(&fds);  //leere die Bitmaske
        FD_SET(s,&fds); //füge fds in die Überwachungsmaske ein
        FD_SET(0,&fds); //füge stdin (0) in die Überwachungsmaske ein
        select(max, &fds, NULL, NULL, tv); //warte auf Eingabe auf 0 (stdin) oder s
    
        if(FD_ISSET(0,&fds))
          //... lese von stdin
        else if(FD_ISSET(s,&fds))
          //... lese vom socket
        else
          //timeout  
      }
      return 0;
    }
    

    siehe auch http://www.ecst.csuchico.edu/~beej/guide/net/html/advanced.html#select und besorg dir am besten "Programmieren von UNIX Netzwerken" von W. Richard Stevens



  • Hey cool!
    Danke, das sieht auf jedenfall schon einmal gut aus.
    So ähnlich hatte ich das auch aber als ich den socketfiledescriptor zum set hinzufügen wollte ist das prog immer mit nem segmentation fault abgestürzt. 🙂

    naja ich werde das jetzt gleich mal ausprobieren und sehen das ich mir das buch zulege 🙂

    ok thx

    bye



  • Vielleicht könnte man noch ergänzend erwähnen, daß man anstatt das Feld in der Hauptschleife immer neu zu belegen auch zwei Felder anlegen kann, bei denen das eine immer zu Anfang eines Schleifendurchlaufs in das andere kopiert wird. Dann gehen ebenfalls keine Deskriptoren verloren, ist schneller und spart auch noch Quelltext.



  • Also ich habe das jetzt mal ausprobiert.
    Allerdings bringt er mir beim belegen des FD_SET mit dem socket einen Segmentation fault und das prog stürzt ab. ich habe das erst mal auskommentiert. das gleiche geschieht ebenfalls wenn der timeout abgelaufen ist. und beim erstmal select() bleibt er ja bei select stehen und wartet oder wie ist das, naja auf jedenfall beim ersten durchlauf gehts mit dem reagieren auf die consoleneingabe (stdin) allerdings durchläuft er dann die schleife ohne unterbrechung und hält nicht mehr an um halt auf eingaben zu warten.

    ich hoffe ihr könnt mir da weiterhelfen.

    ansonsten ist das das was ich gesucht habe 🙂

    tschü



  • Original erstellt von Inferno2k:
    **naja auf jedenfall beim ersten durchlauf gehts mit dem reagieren auf die consoleneingabe (stdin) allerdings durchläuft er dann die schleife ohne unterbrechung und hält nicht mehr an um halt auf eingaben zu warten.
    **

    Du musst den Tastaturpuffer leeren oder das line buffering deaktivieren und zeichenweise von stdin zu lesen.



  • Hi ihr!

    Also ich hab soweit alles hinbekommen allerdings bis auf eine sache.

    Also wenn ich bei mir bei select() den ersten parameter auf max (d.h. den socket file descriptor plus 1 sezte bricht das prog mit segmentation fault ab. deswegen habe ich probiert nur den wert des sockfd dort einzusetzen dann trat der fehler nicht mehr auf. nun ist es allerdings so das er zwar auf consoleneingaben reagiert und auch der timer funktioniert aber er reagiert nicht auf socket ereignisse das heißt ich kann ned auswerten ob am socket man gelesen werden muss.

    vielleicht könnt ihr mir mal ein testprog schreiben was bei euch funzt und ich teste es dann mal bei mir. wäre echt cool.

    wer mir etwas schicken will sagt einfach bescheid.

    also dann thx für die hilfe 🙂

    bye

    [ Dieser Beitrag wurde am 26.12.2002 um 19:03 Uhr von Inferno2k editiert. ]



  • Original erstellt von kingruedi:
    **```cpp
    if(FD_ISSET(0,&fds))
    //... lese von stdin
    else if(FD_ISSET(s,&fds))
    //... lese vom socket
    else
    //timeout

    Ist es hier ausgeschlossen, dass stdin und socket "gleichzeitig" also in einem Durchlauf Daten liefern - oder müsste ich in jedem Schleifendurchlauf beide auf FD_ISSET abfragen?

    [ Dieser Beitrag wurde am 06.01.2003 um 13:20 Uhr von pfalzmarc editiert. ]



  • Könntet ihr noch mal ein ganzes programm posten, das funzt, da mich das auch interessieren würde.



  • Hat sich erledigt! FD_ISSET liefert solange > 0 bis die Daten tatsächlich gelesen wurden - d.h. if-else funktioniert problemlos!

    @James

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    int main(void)
    {
        fd_set rfs;
        struct timeval wait;
        int n;
    
        while(1)
        {
            wait.tv_sec=1;
            wait.tv_usec=0;
    
            FD_ZERO(&rfs);
            FD_SET(0,&rfs);
            n=select(1,&rfs,NULL,NULL,&wait);
            if(!FD_ISSET(0,&rfs)) //timeout
            {
                printf("tralala\n\r");
            }
            else //Data
            {
               printf("Daten sind da - ich lese aber nicht\n\r");
            }
        }
    
        return 0;
    }
    

    [ Dieser Beitrag wurde am 06.01.2003 um 15:52 Uhr von pfalzmarc editiert. ]



  • Hi alle zusammen!

    Also ich habs mit dem Buch und den Beispielen fast hinbekommen.

    Also die Reaktion auf Ereignisse an der Standardeingabe und am Socket funktionieren soweit. Habs dann so gemacht das das prog, wenns am socket was gibt eine function aufruft in der die daten gelesen werden und anschließen ausgegeben werden. das functioniert soweit aber er gibt nun diese daten die gelesen wurden, (is nur ne textzeile) in einer endlosschleife aus also das prog schreibt immer wieder die eine zeile hin. und ich bin mir ziemlich sicher das die zeile nur einmal gesendet wurde.

    zum lesen benutze ich übrigens die read() function und die ausgabe erfolgt über fputs()

    ich glaube der hält dann nicht mehr an der select() function an.

    muss ich da noch irgendwas "leeren" irgendeinen puffer oder was weiß ich?

    ich hoffe ihr könnt mir da helfen. Wenn ich den wichtigsten code posten soll oder ihn jemandem schicken soll sagt einfach bescheid.

    ok cu



  • wenn beim read() ein Fehler auftritt (z.B. die Socketverbindung getrennt wurde) erhältst Du den Rückgabewert -1. Dann darfst Du das Handle auf die Socketverbindung nicht mehr in Deine select-Maske miteinbinden.



  • Hi alle zusammen!

    Habs hinbekommen, Danke nochmal für die Hilfe!

    Hab aber mal noch ne Frage:

    Wenn ich was senden will hab ich folgendes Problem:

    wenn ich das eingegebene an der console direkt weitersende quasi wie ein chat dann funktioniert das.
    Beispiel:

    if (fgets(sendline, MAXLINE, fp) == NULL)
      return;
    write(sockfd, sendline, strlen(sendline));
    

    so geht alles aber wenn ich das so mache geht es nicht:

    if (fgets(Command, MAXLINE, fp) == NULL)
      return;
    

    //... Auswertungen des eingelesenen Commandos (Command)

    und nun sende ich zum Beispiel in einer anderen function
    anhand des Commandos die entsprechende Textzeile. Diese stelle ich zumsammen und sende sie dann so:

    write(sockfd, TextZeile, strlen(TextZeile));
    

    naja ich hoffe ihr wißt was ich meine weil es doch ein bissle kompliziert ist das alles zu erklären.

    thx schon mal für eure hilfe 🙂

    Tschü

    [ Dieser Beitrag wurde am 25.01.2003 um 14:34 Uhr von Inferno2k editiert. ]


Anmelden zum Antworten