socket client-> auf antwort warten und gleichzeitig eingaben empfangen



  • hallo

    do 
      { 
        FD_ZERO(&fdset); 
        FD_SET(s,&fdset); 
        select(0,&fdset,NULL,NULL,NULL); 
        rc=recv(s,antwort,256,0); 
        if(rc!=0) 
        { 
          antwort[rc]='\0'; 
          cout<<"server antwortet: "<<antwort<<endl; 
        } 
        cout<<name<<" : "; 
        cin>>buf; 
    
        strcpy(nachricht,name); 
        strcat(nachricht,": "); 
        strcat(nachricht,buf); 
    
        send(s,nachricht,strlen(nachricht),0); 
    
      }while(buf[0]!='q');
    

    problem: ich bekomme nur daten vom server gesendet wenn der nutzer eine eingabe betätigt hat

    cin>>buf;
    

    .durch diese eingabeaufforderung bleibt mein programm solange stecken bis der nutzer was eingegeben hat (wie üblich).gibt es eine möglichkeit gleichzeitig daten zu empfangen/senden und gleichzeitig eingaben des nutzers entegegen zu nehmen?

    tschüss



  • Am besten, du spendierst dem Senden/Empfangen einen eigenen Thread. Allerdings mußt du die Kommunikation dann natürlich z.B. via Mutex mit den Benutzereingaben synchronisieren.



  • hi

    kennst du ein(ige) gut(e) tutorial(s) zu threads?
    -hab noch nie etwas mit threads zu tun gehabt

    -mutex 😕

    cYa



  • Hab jetzt kein konretes zur Hand, aber google wird dir schon nen Haufen ausspucken. Such halt nach threads, multithreading, synchronisation und dergleichen.
    Ich persönlich arbeite gerad mit der Boost-Library, die auch standardkonforme Klassen für Threading bereitstellt und bin damit sehr zufrieden.



  • Du kannst select() auch auf stdin anwenden.



  • Nein. Es gibt keine Möglichkeit, festzustellen, ob sich bereits Zeichen im Puffer von stdin befinden. Aber zum Glück gehts hier um cin, und da gibt es die Funktionen in_avail und readsome, mit denen man sich hoffentlich was zurechtbasteln kann.



  • hm? In der select-manpage gibts doch ein Beispiel, was genau dass macht.



  • Hallo,
    ich verschiebe das mal nach Rund um, da weder select noch Threads noch Sockets Standard-C++ sind.



  • DrGreenthumb: Nö, das Beispiel überwacht fd 0. stdin ist ein gepufferter Überbau dazu, und den Status des Puffers kannst du nicht abfragen.



  • hallo

    Du kannst select() auch auf stdin anwenden

    ....select bringt ja auch nicht das programm zum stehen...frag mich nur wie dann der nutzer seine eingaben betätigen kann wenn das select das prog in den "schlaf" modus setzt..?

    tschüss



  • Hi,

    ich hatte vor kurzem im C++-Forum einen mehrseitigen Thread zu diesem Thema gehabt und auch Antworten gekriegt.

    Lösungen, die ich rausgefunden jetzt kenne:
    - Eigener Thread für Ein-/Ausgabe (gut, aber es gibt keine Ausgabe, während was eingegeben wird, sonst wird ja die Eingabe zermatscht)
    - select() auf stdin (nicht getestet und gleiches Problem wie bei Threading)
    - Neue Konsole für Eingabe + Eigener Thread (geht bestimmt, aber wahrscheinlich nicht portabel und frag' mich nicht wie)
    - Keine Eingabe, eigenes Tool coden, dass per Socket auf den Server connecten und Kommandos absetzen kann

    ChrisM



  • Bashar schrieb:

    DrGreenthumb: Nö, das Beispiel überwacht fd 0. stdin ist ein gepufferter Überbau dazu, und den Status des Puffers kannst du nicht abfragen.

    aha, hm, aber ist das nicht egal? Das Problem ist ja, dass das Programm bei der Eingabe blockiert. Und mit dem Beispiel aus der Manpage ist das nicht der Fall.

    rulzmaker schrieb:

    ....select bringt ja auch nicht das programm zum stehen...frag mich nur wie dann der nutzer seine eingaben betätigen kann wenn das select das prog in den "schlaf" modus setzt..?

    select() wartet ja nur solange, bis sich was bei den Filedeskriptoren tut. Wenn man also was eingibt und Enter drückt, kehrt select zurück und man kann von stdin lesen.

    @ChrisM
    Damit deine nicht Eingabe zermatscht wird, müsstest du die Cursorposition entsprechend ändern, bräuchtest als noch ncurses oder sowas.



  • DrGreenthumb schrieb:

    Bashar schrieb:

    DrGreenthumb: Nö, das Beispiel überwacht fd 0. stdin ist ein gepufferter Überbau dazu, und den Status des Puffers kannst du nicht abfragen.

    aha, hm, aber ist das nicht egal? Das Problem ist ja, dass das Programm bei der Eingabe blockiert. Und mit dem Beispiel aus der Manpage ist das nicht der Fall.

    Nein, ist nicht egal. Wenn du auf fd 0 selectest, und Aktivität angezeigt wird, was tust du dann? Du liest mit stdio-Funktionen von stdin ... aber wieviel liest du? Liest du zuwenig, verbleiben Zeichen im Puffer, so dass select beim nächsten mal blockiert, obwohl noch Eingaben zu verarbeiten sind. Liest du zuviel, blockiert die Eingabe, bevor select zum Zuge kommt.
    Das Beispiel aus der Manpage (reden wir vom gleichen Beispiel?) liest ja keine Eingabe, sondern macht nur einmalig ein select auf fd0 mit einem Timeout.



  • Und das heißt jetzt man dürfte nur mit dem lowlevel-read() von fd 0 einlesen, anstatt mit den stdio-Funktionen?
    Aber auch dann weiß man doch nicht wieviel Zeichen man einlesen soll 😕

    Dachte mir das so, dass select zurückkehrt wenn der Benutzer enter gedrückt hat, also genau eine Zeile eingeben hat. Die liest man dann ein und fertig.

    (Mehr als mit select rumgespielt hab ich bisher eh noch nie, aber da hat's immer so funktioniert.)



  • Bashar schrieb:

    Das Beispiel aus der Manpage (reden wir vom gleichen Beispiel?) liest ja keine Eingabe, sondern macht nur einmalig ein select auf fd0 mit einem Timeout.

    Ja, stimmt. Den Einlesepart hab ich selber dazu gedichtet 🙂



  • DrGreenthumb schrieb:

    Und das heißt jetzt man dürfte nur mit dem lowlevel-read() von fd 0 einlesen, anstatt mit den stdio-Funktionen?
    Aber auch dann weiß man doch nicht wieviel Zeichen man einlesen soll 😕

    Doch: Entweder, man fordert mehr Zeichen an, als vorhanden sind. Das kann man am Rückgabewert von read erkennen. Oder man liest weniger als vorhanden sind (oder genau gleich viele), dann gibt select beim nächsten Aufruf gleich wieder die 0 als bereit zurück.

    Dachte mir das so, dass select zurückkehrt wenn der Benutzer enter gedrückt hat, also genau eine Zeile eingeben hat. Die liest man dann ein und fertig.

    Kann man machen, aber während man z.b gerade den Socket abarbeitet könnte der Benutzer zweimal Enter drücken ... was dann?



  • hio

    short int rc;
      SOCKET s;
      SOCKADDR_IN addr;
      FD_SET fdset;
      char antwort[200];
      int ilen;
      char buf[200];
    
    rc=startWinsock();
    
      s=socket(2,SOCK_STREAM,0);
    
      memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten 
      addr.sin_family=2;
      addr.sin_port=htons(12345); // wir verwenden mal port 12345
      addr.sin_addr.s_addr=inet_addr("127.0.0.1"); // zielrechner ist unser eigener
      rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
      send(s,getNachricht(hwndNick),100,0);
    do{
      select(0,&fdset,NULL,NULL,NULL);
      rc=recv(s,antwort,256,0);
      if(rc!=0)
      {
         antwort[rc]='\0';
         SendMessage(hwndGet,WM_SETTEXT,0,(long)antwort);
       }
      }while(true);
    

    durch die fußgesteuerte schleife stürzt mein programm ab..wie wende ichd as select an, mache ich etwas falsch?
    cYa



  • danke bashar

    rulzmaker, da fehlen jetzt die FD_-Makros. Ausserdem muss das erste Argument für select der Deskripter mit der höchsten Nummer + 1 sein, also hier s+1.



  • hi

    fd_makros..hu?

    void startVerbindung()
    {
      rc=startWinsock();
    
      s=socket(2,SOCK_STREAM,0);
    
      memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten 
      addr.sin_family=2;
      addr.sin_port=htons(12345); // wir verwenden mal port 12345
      addr.sin_addr.s_addr=inet_addr(getNachricht(hwndHost)); // zielrechner ist unser eigener
      rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
      send(s,getNachricht(hwndNick),100,0);
    
      select(0,&fdset,NULL,NULL,NULL);
      FD_ZERO(&fdset);
      FD_SET(s,&fdset);
      rc=recv(s,antwort,256,0);
      if(rc!=0)
      {
         antwort[rc]='\0';
         SendMessage(hwndGet,WM_SETTEXT,0,(long)antwort);
       }
    }
    

    s+1 ist nur für linux relevant nicht jedoch für windows.

    cYa



  • rulzmaker schrieb:

    fd_makros..hu?

    FD_ZERO, FD_SET um den socket hinzuzufügen. Das muss vorm select()-Aufruf passieren.

    s+1 ist nur für linux relevant nicht jedoch für windows.

    achso


Anmelden zum Antworten