Fragen zur aus und Eingabe auf der Konsole Konsole



  • Hallo,
    ich würde gern zur übung folgendes Problem lösen:
    ich habe einenen socketserver für mehrere clients als Wndlosschleife, diese macht dann auch Ausgaben in die Konsole,
    nun möchte ich aber das man auch gleichzeitig eine Eingabe machen kann um die serverschleife zu steuern.

    Qausie die unterste Zeile der Konsole meine bfehlseingabe bildet.

    Ich habe mir gedacht das über threads zu lösen, aber geht es dann auch einfach umzusetzen das man in eien Konsolen fenster gleichzeitig eine eingabe und eine laufende ausgabe macht?

    bei Threads habe ich dann noch eine Frage ob c++ auch eine allgemein gültige thread lösung hat, habe was von std::thread gelesen, habe aber im netz bisher nur dürftig informationen dazu gefunden. Oder muss ich warten bis boost in c++ implementiert wird.

    Ich würde den code gern Crossplatform fähig halten ^^

    Gruß
    ^^



  • Threads sind eine schlechte Idee hat aus erst diesen Gedanken, habe aber den entscheidenen Tipp im Forum bekommen.
    Epoll unter Linux, kqueue unter BSD/Solaris oder IOCP unter Windows sollte sein was du suchst.
    Zu epoll und kqueue kann ich sagen das die einfach zu programmieren sind zu IOCP kann ich nichts sagen.



  • für epoll habe ich jetzt nur beispiele gefunden, welche ähnlich funktioniern wie select()

    hier mal mein server code (ist im grunde das server tutorial von www.c-worker.ch)

    #include <windows.h>
    
    #include <winsock2.h>
    
    #include <stdio.h>
    #define MAX_CLIENTS 10
    //Prototypen
    
    int startWinsock(void);
    
    int main()
    {
    
        int rc;
    
        SOCKET acceptSocket;
        //SOCKET connectedSocket;
        SOCKADDR_IN addr;
        char buf[256];
        char buf2[300];
    
        // zusätzliche Variabeln
        FD_SET fdSet;
        SOCKET clients[MAX_CLIENTS];
        int i;
    
        // Winsock starten
    
        rc=startWinsock();
    
        if(rc!=0)
        {
    
            printf("Fehler: startWinsock, fehler code: %d\n",rc);
    
            return 1;
    
        }
        else
        {
    
            printf("Winsock gestartet!\n");
    
        }
    
        // Socket erstellen
    
        acceptSocket=socket(AF_INET,SOCK_STREAM,0);
    
        if(acceptSocket==INVALID_SOCKET)
        {
    
            printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    
            return 1;
    
        }
        else
        {
    
            printf("Socket erstellt!\n");
    
        }
    
        memset(&addr,0,sizeof(SOCKADDR_IN));
    
        addr.sin_family=AF_INET;
    
        addr.sin_port=htons(12345);
    
        addr.sin_addr.s_addr=ADDR_ANY;
    
        rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
    
        if(rc==SOCKET_ERROR)
        {
    
            printf("Fehler: bind, fehler code: %d\n",WSAGetLastError());
    
            return 1;
    
        }
        else
        {
    
            printf("Socket an port 12345 gebunden\n");
    
        }
    
        rc=listen(acceptSocket,10);
    
        if(rc==SOCKET_ERROR)
        {
    
            printf("Fehler: listen, fehler code: %d\n",WSAGetLastError());
    
            return 1;
    
        }
        else
        {
    
            printf("acceptSocket ist im listen Modus....\n");
    
        }
    
        //clients initialisieren
        for(i=0;i<MAX_CLIENTS;i++)
        {
            clients[i]=INVALID_SOCKET;
        }
    
        while(1)
        {
    
            FD_ZERO(&fdSet); // Inhalt leeren
            FD_SET(acceptSocket,&fdSet); // Den Socket der verbindungen annimmt hinzufügen
    
            // alle gültigen client sockets hinzufügen (nur die die nicht INVALID_SOCKET sind)
            for(i=0;i<MAX_CLIENTS;i++)
            {
                if(clients[i]!=INVALID_SOCKET)
                {
                    FD_SET(clients[i],&fdSet);
                }
            }
    
            rc=select(0,&fdSet,NULL,NULL,NULL); // nicht vergessen den ersten parameter bei anderen betriebssystem anzugeben
            if(rc==SOCKET_ERROR)
            {
                printf("Fehler: select, fehler code: %s\n",WSAGetLastError());
                return 1;
            }
    
            // 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;
                    }
                }
            }
    
            // prüfen wlecher 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);
                    }
                }
            }
        }
        closesocket(acceptSocket);
        WSACleanup();
        return 0;
    
    }
    
    int startWinsock(void)
    
    {
    
        WSADATA wsa;
    
        return WSAStartup(MAKEWORD(2,0),&wsa);
    
    }
    

    nur mein problem ist, wie kann man den server nun sauber abschalten?



  • Ich mache das (grob beschrieben) so, dass ich listen in einem Thread ausführe, dem ich den Socket(zeiger) als Parameter übergebe.
    Im Hauptthread warte ich dann zB auf eine Eingabe, und wenn ich den Server beenden will, schließe ich den listen - Socket, so dass der listen - Thread beim Accept einen Fehler bekommt, und sich sauber beenden kann.



  • nun fehlt nur noch die gescheite aus und eingabe von text in die console für die server anwendung

    Eingabe zur steuerung und ausgabe zur kontrolle ähnlich wie bei manchen Linux Programmen, wo könnte man dort ansetzen?



  • 2ten thread



  • schon klar, aber wie unterteilt man das "konsolen" fenster in einen Eingabe bereich und einen Ausgabe bereich?

    wenn man in der Laufenden ausgabe etwas mit std::cin abfragt wird das doch sehr abenteuerlich.



  • du brauchst sowas wie eine gotoxy funtkion, die den cursor an die gewünschte stelle setzt.


Anmelden zum Antworten