tcp server



  • #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <iostream>
    #include <stdlib.h>
    #include <string>
    #include <ctype.h>
    #include <pthread.h>
    #include <sstream>
    
    using namespace std;
    
    #define PORT 1550
    #define MAX_MSG 100
    #define LINE_ARRAY_SIZE (MAX_MSG+1)
    
    void *fchatter(int *connectSocket)
    {
    
    	char line[LINE_ARRAY_SIZE];
        memset(line, 0x0, LINE_ARRAY_SIZE);
        while (recv(*connectSocket, line, MAX_MSG, 0) > 0) {
          cout << "  --  " << line << "\n";
    
          int i;
          for (i = 0; line[i] != '\0'; i++)
            line[i] = toupper(line[i]);
    
          if (send(*connectSocket, line, strlen(line) + 1, 0) < 0)
            cerr << "Error: cannot send modified data";
    
          memset(line, 0x0, LINE_ARRAY_SIZE);  // set line to all zeroes
        }
    }
    
    int main()
    {
      int listenSocket, connectSocket, i;
      unsigned short int listenPort;
      socklen_t clientAddressLength;
      struct sockaddr_in clientAddress, serverAddress;
      char line[LINE_ARRAY_SIZE];
    
      listenPort = PORT;
    
      listenSocket = socket(AF_INET, SOCK_STREAM, 0);
      if (listenSocket < 0) {
        cerr << "cannot create listen socket";
        exit(1);
      }
    
      serverAddress.sin_family = AF_INET;
      serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
      serverAddress.sin_port = htons(listenPort);
    
      if (bind(listenSocket,
               (struct sockaddr *) &serverAddress,
               sizeof(serverAddress)) < 0) {
        cerr << "cannot bind socket";
        exit(1);
      }
    
      listen(listenSocket, 5);
    
      while (1) {
        cout << "Waiting for TCP connection on port " << listenPort << " ...\n";
    
        clientAddressLength = sizeof(clientAddress);
        connectSocket = accept(listenSocket,
                               (struct sockaddr *) &clientAddress,
                               &clientAddressLength);
        if (connectSocket < 0) {
          cerr << "cannot accept connection ";
          exit(1);
        }
    
        cout << "  connected to " << inet_ntoa(clientAddress.sin_addr);
    
        cout << ":" << ntohs(clientAddress.sin_port) << "\n";
    
        pthread_t chatter;
        cout << "1" << connectSocket << endl;
        pthread_create(&chatter, NULL,&fchatter,(int *) connectSocket);
      }
    }
    

    sobald sich ein client verbindet beendet sich der server mit segmentation fault 😕



  • moin,

    du bindest zum Ersten die stdlib.h zweimal ein!
    Wo und wann bricht er denn ab, was spricht der debugger?



  • steff schrieb:

    moin,

    du bindest zum Ersten die stdlib.h zweimal ein!
    Wo und wann bricht er denn ab, was spricht der debugger?

    danke,
    hab den gdb zuvor noch nie verwendet

    (gdb) r
    Starting program: /root/tpchatd
    [New Thread 1024 (LWP 23465)]
    Waiting for TCP connection on port 1550 ...
    connected to xxx.xxx.30.233:1554
    18
    [New Thread 2049 (LWP 23473)]
    [New Thread 1026 (LWP 23474)]
    Waiting for TCP connection on port 1550 ...

    Program received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 1026 (LWP 23474)]
    0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:31
    31 cerr << "Error: cannot send modified data";
    (gdb)

    memset(line, 0x0, LINE_ARRAY_SIZE)
    

    hab ich raus weil line sowieso nur in der funktion steht

    kann die ausgabe vom gdb jemand interpretieren?
    ich bin da noch etwas überfordert



  • debian inside schrieb:

    memset(line, 0x0, LINE_ARRAY_SIZE)
    

    hab ich raus weil line sowieso nur in der funktion steht

    Daran wirds aber IMO nicht liegen, weil diese Zeile korrekt ist.

    kann die ausgabe vom gdb jemand interpretieren?
    ich bin da noch etwas überfordert

    Nach einem SIGSEGV fragt man denn gdb üblicherweise noch "where". Tu das und wir wissen mehr. 😉



  • debian inside schrieb:

    if (send(*connectSocket, line, strlen(line) + 1, 0) < 0)
    

    Dumme Frage, aber warum "strlen(line)+1"?



  • nman schrieb:

    debian inside schrieb:

    if (send(*connectSocket, line, strlen(line) + 1, 0) < 0)
    

    Dumme Frage, aber warum "strlen(line)+1"?

    +1 stellt der rückgabe ein leerzeichen voran

    wenn ich connectSocket als globalen int verwende klappts
    ich versteh die übergabe von pthread_create in die funktion nicht

    wenn der socket in main 8 hat wir er durch diese übergabe 0x8 😕



  • 0x8 ist eine Hexadezimalzahl und eine andere Darstellung für Dezimal 8 🙄

    Und das +1 sorgt nur dafür, dass eine terminierende 0 mit gesendet wird.

    Schau mal mit bt nach dem genaueren Fehler (mit -g vorher kompilieren).



  • kingruedi schrieb:

    0x8 ist eine Hexadezimalzahl und eine andere Darstellung für Dezimal 8 🙄

    Und das +1 sorgt nur dafür, dass eine terminierende 0 mit gesendet wird.

    Schau mal mit bt nach dem genaueren Fehler (mit -g vorher kompilieren).

    wirkt sich die darstellung auch irgendwie aus?

    (gdb) bt
    #0 0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:32
    #1 0x4001e0ba in pthread_start_thread () from /lib/libpthread.so.0
    #2 0x4001e101 in pthread_start_thread_event () from /lib/libpthread.so.0
    (gdb)

    keine ahnung ob ich das richtig interpretiere aber hier siehts doch so aus wie wenn die hex darstellung probleme macht oder?



  • 0x080491b3 in fchatter (connectSocket=0x8) at tpchatd.cpp:31

    Der Pointer connectSocket mit der Adresse 0x8 sieht nicht sehr koscher aus!

    Wenn man dan schaut wo und wie die Funktion aufgerufen wird, stellt man folgendes fest:

    pthread_create(&chatter, NULL,&fchatter,(int 😉 connectSocket);

    Du castest einen Integer in einen Pointer auf einen Integer.

    Jetzt ein kleiner Blick auf deine Threadfunction

    void *fchatter(int *connectSocket)

    Jetzt muss dir bewusst sein, was connectSocket in Wirklichkeit ist. Ein Pointer auf ein Integer? Nein! Ein Integer gecasted als Pointer auf einen Integer! Also dereferenzieren ist nicht!

    Die libpthread hat nicht umsonst den Parameter als void-Pointer definiert.

    mfg Unixer

    P.S.: Eigne dir die Basics über Pointer an



  • alle threads benutzen das selbe client socket...
    sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
    wird der socket von thread a ueberschrieben. boese.

    int clientSocket;
    
    clientSocket = accept(...);
    ...
    pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket );
    /*
     -> clientSocket liegt auf dem stack, jeder thread besitzt einen zeigen
        auf die selbe int-var
    */
    

    -> moegliche loesung: jedem thread ein mit malloc/new erzeugtes int uebergeben
    (der thread raeumts am ende auf).



  • alle threads benutzen das selbe client socket...
    sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
    wird der socket von thread a ueberschrieben. boese.

    Falsch!

    Es heisst:

    pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket );
    

    und nicht

    pthread_create(&chatter, NULL,&fchatter,(int *) &clientSocket );
    

    Man achte auf das kleine aber feine '&'

    mfg unixer



  • -> moegliche loesung: jedem thread ein mit malloc/new erzeugtes int uebergeben(der thread raeumts am ende auf).

    Ansich ist es kein Problem den Descriptor als Param (also der void-Pointer-Parameter) zu übergeben. Man muss beachten, dass man ihn dan auch wirklich als Descriptor verwendet und nicht als Pointer.

    unixer



  • unixer schrieb:

    alle threads benutzen das selbe client socket...
    sendet thread a und es connected ein neuer client (->thread b wird erzeugt)
    wird der socket von thread a ueberschrieben. boese.

    Falsch!

    Es heisst:

    pthread_create(&chatter, NULL,&fchatter,(int *)clientSocket );
    

    und nicht

    pthread_create(&chatter, NULL,&fchatter,(int *) &clientSocket );
    

    Man achte auf das kleine aber feine '&'

    mfg unixer

    super. wenn du glueck hast funktioniert das tatsaechlich.
    ansi c garantiert das nicht. das funktioniert nur, solange
    ein int kleiner oder gleich der groesse eines zeigers ist;
    was zwar oft aber nicht zwingend der fall ist.

    machs lieber indem fuer fuer jeden thread ein int allokierst
    da bist du auf der sicheren seite.



  • super. wenn du glueck hast funktioniert das tatsaechlich.
    ansi c garantiert das nicht. das funktioniert nur, solange
    ein int kleiner oder gleich der groesse eines zeigers ist;
    was zwar oft aber nicht zwingend der fall ist.

    Das ist wahr! Aber ich kenn keine Architektur, auf der die libpthread läuft, bei der das der Fall ist. IMHO muss man nicht solch einen Mehraufwand betreiben um diesen _sehr_ theoretischen Fall abzudecken.

    mfg unixer



  • unixer schrieb:

    super. wenn du glueck hast funktioniert das tatsaechlich.
    ansi c garantiert das nicht. das funktioniert nur, solange
    ein int kleiner oder gleich der groesse eines zeigers ist;
    was zwar oft aber nicht zwingend der fall ist.

    Das ist wahr! Aber ich kenn keine Architektur, auf der die libpthread läuft, bei der das der Fall ist. IMHO muss man nicht solch einen Mehraufwand betreiben um diesen _sehr_ theoretischen Fall abzudecken.

    mfg unixer

    danke

    fazit:
    es darf nicht immer die selbe threadid, der selbe socket verwendet werden und ich seh mir pointer an



  • Igitt, ich weiß schon, warum ich kein C mag. 😉



  • so das läuft jetzt
    nicht unbedingt schön programmiert aber is ja schon spät und war ein langer tag 😉

    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <iostream>
    #include <string>
    #include <ctype.h>
    #include <pthread.h>
    #include <sstream>
    
    using namespace std;
    
    #define PORT 1550
    #define MAX_MSG 100
    #define LINE_ARRAY_SIZE (MAX_MSG+1)
    #define MAX_THREADS 5
    
    int threads = 0;
    int thread = 0;
    
    int connectSocket[MAX_THREADS];
    
    int threadrotate();
    void *fchatter(int* thisthread)
    {
        int temp = (int) thisthread;
        char line[LINE_ARRAY_SIZE];
        memset(line, 0x0, LINE_ARRAY_SIZE);
        while (recv(connectSocket[temp], line, MAX_MSG, 0) > 0) {
          cout << "Thread" << temp << ": " << line << "\n";
    
          int i;
          for (i = 0; line[i] != '\0'; i++)
            line[i] = toupper(line[i]);
    
          //if (send(connectSocket[temp], line, strlen(line) + 1, 0) < 0)
          if (send(connectSocket[temp], line, strlen(line), 0) < 0)
            cerr << "Error: cannot send modified data"; 
          memset(line, 0x0, LINE_ARRAY_SIZE);
        }
        cout << "Thread" << temp << " end" << endl;
        connectSocket[temp] = 0;
        threads--;
    }
    
    int main()
    {
      int listenSocket, i;
      unsigned short int listenPort;
      socklen_t clientAddressLength;
      struct sockaddr_in clientAddress, serverAddress;
      char line[LINE_ARRAY_SIZE];
    
      listenPort = PORT;
    
      listenSocket = socket(AF_INET, SOCK_STREAM, 0);
      if (listenSocket < 0) {
        cerr << "cannot create listen socket";
        exit(1);
      }
    
      serverAddress.sin_family = AF_INET;
      serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
      serverAddress.sin_port = htons(listenPort);
    
      if (bind(listenSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
        cerr << "cannot bind socket";
        exit(1);
      }
    
      listen(listenSocket, 5);
    
     pthread_t chatter[MAX_THREADS];
      while (1) {
    	while (threads<=MAX_THREADS)
    	{
    	    cout << "Waiting for TCP connection on port " << listenPort << " ...\n";
    
    	    cout << threads << " Threads running" << endl;
    	    clientAddressLength = sizeof(clientAddress);
    	    thread = threadrotate();
    	    connectSocket[thread] = accept(listenSocket, (struct sockaddr *) &clientAddress, &clientAddressLength);
    	    if (connectSocket[thread] < 0) {
    	      cerr << "cannot accept connection ";
    	      exit(1);
    	    }
    
    	    cout << "  connected to " << inet_ntoa(clientAddress.sin_addr);
    
    	    cout << ":" << ntohs(clientAddress.sin_port) << "\n";
    	    pthread_create(&chatter[thread], NULL,&fchatter,(int *) thread);
    	    threads++;
    	}
      }
    }
    
    int threadrotate()
    {
        int f = 0;
        while(connectSocket[f]!=0) f++;
        return f;
    }
    


  • wäre es möglich das jemand mit einer der beiden versionen ne ddos attacke ausführt?



  • wäre es möglich das jemand mit einer der beiden versionen ne ddos attacke ausführt?

    DDos Attacken sind prinzipiell immer möglich, unabhängig von der verwendeten Serversoftware..

    Igitt, ich weiß schon, warum ich kein C mag. 😉

    Findest wohl static_cast<void *>(var) schöner als (void 😉 var 😉

    mfg unixer



  • debian inside schrieb:

    so das läuft jetzt
    void *fchatter(int* thisthread)
    {
    int temp = (int) thisthread;
    ...
    }
    ...
    cout << ":" << ntohs(clientAddress.sin_port) << "\n";
    pthread_create(&chatter[thread], NULL,&fchatter,(int 😉 thread);
    threads++;
    }
    }
    }
    [/cpp]

    jetzt haste ne mischloesung 🙂

    wichtig ist, dass der hauptthread (in dem das accept ist)
    den socket-fd kopiert.
    theoretisch kann es passieren, dass der hauptthread einen neuen
    socket annimmt bevor der worker-thread den alten socket-fd kopiert
    hat.

    du wirst um ein dynamisches allokieren eines neuen socket-fd nicht
    drum rum kommen.

    wenn du das programm nur fuer private zwecke hast, nimm die loesung
    von unixer; d.h. lass das "(int 😉 thread" stehen und gud is.


Anmelden zum Antworten