Thread: Issue with multi-threaded tcp server

  1. #1
    Registered User
    Join Date
    Jan 2011
    Posts
    41

    Issue with multi-threaded tcp server

    Hey everyone,

    I have a client program that is supposed to send the server two numbers and the server is supposed to return the sum of those numbers. The server has to be multi-threaded because in th context of my project, any number of clients can connect at once. Basically whats happening is if I connect 3 clients to the server, only the last one gets results, and im not really sure why. I've been working on it for a few hours and I can't seem to find the error.

    anyway here is the loop where I spawn my threads:
    Code:
          while (1)
          {
          /* accept a connection from a client program */
             int newFD;
    	pthread_t tid;
    			
             newFD = accept( socketFD, (struct sockaddr *)&srcAddr, (socklen_t *)&fromlen );
             if ( newFD < 0 )
             {
                perror( "NATbox:accept()" );
                return -1;
             }
          
             int threadError = pthread_create(&tid, NULL, respond, (void *) newFD); 
             if(threadError < 0)
             {
                perror("NATbox:spawn thread\n");
                return -1;
             }
          }
       	
          int status;
          int i = 0;
          while( i != -1 ) 
          {
             i = wait( &status );
             printf( "Finished pid = %d\n", i );
          }
    And here is the function that each thread calls:
    Code:
    /**
     * function that responds to client requests 
     * adds two numbers received from the client
     * then returns the result
     */
       void * respond( void * incomingRequestFD )
       {
          int buffer[2];
          int retVal = 1;
          int value;
          char response[3];
       	
       	//copy socket 
         int newFD = *(int * ) incomingRequestFD;
       	
          printf("socket: %d\n", newFD);
       	/* receive data from the sender */
          while(retVal != 0 )
          {
             retVal = recv(newFD, buffer, sizeof(buffer), 0);
             if(retVal < 0)
             {
                perror("add_server:recv()");
                exit(1);
             } 	
             printf("received: %d\t%d\n", buffer[0], buffer[1]);
          	/* add the two received numbers together */
             value = buffer[0] + buffer[1];
             printf("value: %d\n", value);
           	/* write the int to the buffer */
             sprintf(response, "%d", value);
          	/* send result to client */
             send(newFD, response, sizeof(response), 0);
          }
       	/* close socket */
          close(newFD);
       
          return 0;
       }/* end respond */
    Thanks,
    Hunter

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    I'm surprised you get that far.

    > int newFD = *(int * ) incomingRequestFD;
    You create the thread passing the newFD as a value, but here you treat it as a pointer.
    How come it doesn't blow up immediately with an invalid address?

    In any event, the FD in your thread function is almost certainly wrong, even if it doesn't crash.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jan 2011
    Posts
    41
    I accept a new connection on newFD(a socket), inside my while loop, then pass that socket to the thread function respond. Since the thread only passes void pointers, I cast it back to an int pointer inside the function so I can receive on it.

    What is the issue with that? I read this online as a way to use sockets passed using threads.

    Hunter

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    If you were expecting to dereference a pointer, you NEED to pass a pointer in to begin with.

    int threadError = pthread_create(&tid, NULL, respond, (void *)&newFD);


    However, this by itself leads to the next problem with running threads, because you're passing a POINTER TO A LOCAL. If that local changes or goes out of scope before your thread gets a hold of the value, you end up in the very situation you describe - several threads all doing the same thing.

    Code:
             newFD = accept( socketFD, (struct sockaddr *)&srcAddr, (socklen_t *)&fromlen );
             if ( newFD < 0 )
             {
                perror( "NATbox:accept()" );
                return -1;
             }
             int *param = malloc( sizeof *param );
             *param = newFD;
             int threadError = pthread_create(&tid, NULL, respond, param);
    Then
    Code:
       void * respond( void * param)
       {
          int *fdptr = param;
          int buffer[2];
          int retVal = 1;
          int value;
          char response[3];
       	
       	//copy socket 
         int newFD = *fdptr;
         free( fdptr );
    So, in the caller, a unique block of memory is allocated for passing parameters to the thread, then OWNERSHIP of that block is passed to the thread. When the thread has done with it, it can free that memory.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Jan 2011
    Posts
    41
    Thanks for pointing that out. I am sure that would have been a future error I ran into. My current issue is not that the 3 threads are doing the same thing, it's that only the last thread created is doing something. Which leads me to believe that I am overwriting my struct somewhere.

    Execution Example:
    Code:
    Start NATServer
    Start Addition Server
    Start Client1
    Start Client2
    
    Client1 connects to NATServer
    struct is empty
    NATServer blocks
    Client2 connects to NATServer
    struct has correct data
    NATServer sends to Addition Server
    Addition Server sends result to NATServer
    NATServer sends result to Client 2
    Hunter


    EDIT:
    I found the error, I was declaring a global struct once, but allocating memory to it which every thread I created, so the newest thread always overwrote the previous threads.

    Hunter
    Last edited by mcmillhj; 03-19-2011 at 02:15 PM. Reason: solved

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. TCP Server cannot save buffer data to mysql !
    By syedmuhd in forum C Programming
    Replies: 5
    Last Post: 09-18-2010, 08:54 PM
  2. Multi Threaded Web server question
    By webznz in forum C Programming
    Replies: 5
    Last Post: 08-07-2010, 05:20 AM
  3. Windows TCP Server Can't Handle >100 Clients
    By Xterria in forum Networking/Device Communication
    Replies: 13
    Last Post: 11-02-2009, 07:21 PM
  4. TCP Sockets: multiple clients - one server
    By Printisor in forum C Programming
    Replies: 4
    Last Post: 11-01-2007, 10:34 AM
  5. socket question
    By Unregistered in forum C Programming
    Replies: 3
    Last Post: 07-19-2002, 01:54 PM