0

I am implementing a mini youtube sort of socket interface. The problem comes when receiving data from my subservers in a threaded main_server, that can easily handle multiple subservers. If i join the thread via pthread_join after the thread creation in main, the thread invocation is successful and the data is received from the subserver, but that technically destroys the whole point of creating a multithreaded subserver environment. If i don't join the thread, this is what the error comes:

Alis-MacBook-Pro:Desktop aliabbasjaffri$ gcc main_server.c -w -lpthread -o s
Alis-MacBook-Pro:Desktop aliabbasjaffri$ ./s

bind = 0 SFD: 3
Thread Created!!!
SFD: 3 Inside thread function!

recvfrom(): Bad file descriptor
ERROR RECEIVING STUFF!!!!!!!!!
Received stuff: 
SubServerNum: -48
Address: 
Bus error: 10

When i join the thread via the pthread_join, the execution is successful and the data is successfully received from the subserver. This is what appears on the terminal.

Alis-MacBook-Pro:Desktop aliabbasjaffri$ gcc main_server.c -w -lpthread -o s
Alis-MacBook-Pro:Desktop aliabbasjaffri$ ./s
bind = 0 SFD: 3
Thread Created!!!
SFD: 3 Inside thread function!

Received stuff: 1,0.0.0.0,8888,hello.mp4,10.0
SubServerNum: 1
Address: 0.0.0.0
Port: 8888
Video Name: hello.mp4
Video Size: 10.000000



Received stuff: 1,0.0.0.0,8888,world.mp4,20.0
SubServerNum: 1
Address: 0.0.0.0
Port: 8888
Video Name: world.mp4
Video Size: 20.000000



Received stuff: end
Exiting the thread!

My Main Server Code is as follows.

#include <netinet/in.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <stdio.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <fcntl.h>

    //////////////////////////////////////////////~~GLOBAL DECLARATIONS~~///////////////////////////

    const int numberOfThreads = 1;              //Number of threads to get data from subservers!
    const int sizeOfVideosStruct = 6;

    int PORT = 8889;                            //port number

    struct sockaddr_in server , client;
    socklen_t len = sizeof( client );

    struct videosList
    {
       int serverNumber;

       char address[30];
       int port;

       char movieName[50];
       int movieSize;
    };

    struct videosList videos[ sizeOfVideosStruct ]; //movies from subservers

    //////////////////////////////////////////////////////////////////////////////////////////////////


    void subserverReplyParserAndEntryManager( char line[] )
    {
        int subServerNumber = 0 , i = 0 , j = 0;
        int port = 0;
        float size = 0;
        char address[20] = "" , RPort[5] = "" , videoName[40] = "" , RSize[6] = "";

        subServerNumber = line[0];
        subServerNumber -= 48;

        printf("SubServerNum: %d\n", subServerNumber );

        for( i = 2;  ; )
        {
            if( line[i] == ',' )
            {
                break;
            }

            address[j++] = line[i++];
        }

        printf("Address: %s\n", address );

        i++;
        j = 0;

        for( ;  ;  )
        {
            if( line[i] == ',' )
            {
                break;
            }

            RPort[j++] = line[i++];
        }

        port = atoi(RPort);

        printf("Port: %d\n", port );

        i++;
        j = 0;  

        for( ;  ;  )
        {
            if( line[i] == ',' )
            {
                break;
            }

            videoName[j++] = line[i++];
        }

        printf("Video Name: %s\n", videoName );

        i++;
        j = 0;

        for( ;  ;  )
        {
            if( line[i] == '\0' )
            {
                break;
            }

            RSize[j++] = line[i++];
        }

        size = atoi(RSize);

        printf("Video Size: %f\n\n\n", size );
    }

    void * subserverThreadFunction( void * threadArgument )
    {
        char data[1000];

        int sfd = ( int ) threadArgument;

        printf("SFD: %d Inside thread function!\n" , sfd);

        while( strcmp( data , "end" ) != 0 )
        {
            if( recvfrom( sfd , data , 1000 , 0 , (struct sockaddr *)&client , &len ) == -1 )
            {
                perror("recvfrom()");
                printf("ERROR RECEIVING STUFF!!!!!!!!!");
            }

            printf("\nReceived stuff: %s\n" , data);

            if( strcmp( data , "end" ) == 0 )
            {
                break;
            }

            subserverReplyParserAndEntryManager( data );
        }

        printf("Exiting the thread!");

        pthread_exit(NULL);
    }


    void sendDataToClient()
    {

    }

    int main() 
    {
        pthread_t thread;
        char buffer1[1024] = "";

        int num = 0 , rc = 0;

        int sfd = socket( AF_INET , SOCK_DGRAM , 0); 

        bzero( &server , sizeof(server) );

        server.sin_family = AF_INET; 
        server.sin_port = htons( PORT ); 
        server.sin_addr.s_addr = inet_addr("0.0.0.0");

        printf( "bind = %d SFD: %d\n" , bind( sfd , (struct sockaddr *)&server , sizeof(server) ) , sfd ); 

        ////////////////////////////////

        for( num = 0; num < numberOfThreads; num++ )
        {
            printf("Thread Created!!!\n");
            rc = pthread_create( &thread , NULL, subserverThreadFunction, (void *) sfd );

            pthread_join( thread , NULL );

            if (rc)
            {
                printf("ERROR; return code from pthread_create() is %d\n", rc);
                exit(-1);
            }
        }

        ///////////////////////////////////


        ///////////////////////////////////

        //printf( "Please enter the query from the client!\n");

        /*

        recvfrom( sfd , buffer1 , 1024 , 0 , (struct sockaddr *)&client , &l ); 
        printf( "Message from client: %s\n" , buffer1);

        printf( "Message to client: " );

        for( int i = 0; i < 5; i++ )
        {
            if( strcmp( listOfVideos[i] , buffer1 ) == 0 )
            {
                printf( "\nOne match found: %s" , listOfVideos[i] );
                sendto( sfd , listOfVideos[i] , strlen( listOfVideos[i] ) , 0 , (struct sockaddr *)&client , l );
            }
        }
        sendto( sfd , "" , strlen( "" ) , 0 , (struct sockaddr *)&client , l );

        */

        ///////////////////////////////////

        //sendto( sfd , buffer2 , strlen(buffer2) , 0 , (struct sockaddr *)&client , l );

        close(sfd);

        printf( "\n" );

        pthread_exit(NULL);

        return 0;
    }

My subserver code is as follows:

#include <netinet/in.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <stdio.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <fcntl.h> 

    int PORT = 8889;

    int main() 
    { 
        int sfd = 0,l = 0, breaker = 0 , i = 0;

        int number = 1;

        char *buffer1[2] , end[4] = "end";

        buffer1[0] = "1,0.0.0.0,8888,hello.mp4,10.0";
        buffer1[1] = "1,0.0.0.0,8888,world.mp4,20.0"; 

        struct sockaddr_in ser; 

        sfd = socket( AF_INET , SOCK_DGRAM , 0 );

        bzero( &ser , sizeof(ser) ); 

        ser.sin_family = AF_INET;
        ser.sin_port = htons( PORT ); 

        inet_aton("0.0.0.0" , &ser.sin_addr);

        while(  breaker != 2 )
        {   
            sendto( sfd , buffer1[i] , strlen( buffer1[i] ) , 0 , (struct sockaddr *)&ser , sizeof(ser) ); 

            printf("\nString sent to server: %d" , i );

            breaker++;
            i++;
        }

        sendto( sfd , end , sizeof(end) + 1 , 0 , (struct sockaddr *)&ser , sizeof(ser) );

        printf("\nData sent successful!");      

        close(sfd);

        printf( "\n" ); 

        return 0;
    }

I am stuck in this for quite a while now and i can't seem to figure out what the problem is. Any help would be extremely appreciated!

Ben
  • 51,770
  • 36
  • 127
  • 149
Ali Abbas Jaffri
  • 153
  • 2
  • 15
  • I think it would be wise for `recvfrom( sfd , data , 1000 , 0 , (struct sockaddr *)&client , &len )` to refer to a `client` and a `len` which are local to the pthread... not global to the process. Also, when the main thread exits, everything else stops dead... so, if the main thread has nothing else to do, but the other threads are busy doing something useful, then the main thread needs to wait for the right time to stop. –  Oct 21 '14 at 15:05
  • Seems to me if you don't join the thread in main() you'll hit the close(sfd); once you're done creating the threads, so now your threads are operating on a closed descriptor. – nos Oct 21 '14 at 15:10
  • @nos, it worked. i got the point that i was actually closing the socket before letting the thread complete its working. That worked up for me. – Ali Abbas Jaffri Oct 21 '14 at 19:04
  • @gmch, if not making global, can you please suggest how can i pass the thread the arguments, that would include the arguments that are necessary for recvfrom() function; the (struct sockaddr *)&client and len.. – Ali Abbas Jaffri Oct 21 '14 at 19:06
  • Ummm... the client address an its length are filled in by recvfrom(), same like the data, so aren't arguments for the thread. –  Oct 21 '14 at 19:51

1 Answers1

1

Without the pthread_join() your server routine creates your new thread, passing in the socket file descriptor and then promptly carries on and closes the newly created socket.

If your creating multiple threads then you need to do something like storing the thread id's in an array and then joining on them outside of the loop that craetes them.

One last thing - do you really mean to pass the same socket descriptor into every thread? If you can I suggest getting a copy of Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition) which will give lots of info on how to create a client/server app.

Jackson
  • 5,627
  • 2
  • 29
  • 48