当在C中的POSIX线程中使用时,recvfrom()给出了错误的文件描述符错误

时间:2014-10-21 14:21:47

标签: c multithreading pthreads recvfrom

我正在实现一个迷你youtube类型的套接字接口。在线程化main_server中从我的子服务器接收数据时会出现问题,这可以轻松处理多个子服务器。如果我在main中创建线程后通过pthread_join加入线程,则线程调用成功并且从子服务器接收数据,但这在技术上破坏了创建多线程子服务器环境的全部意义。如果我没有加入该主题,那就是错误:

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

当我通过pthread_join加入线程时,执行成功并且从子服务器成功接收数据。这就是终端上出现的内容。

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!

我的主服务器代码如下。

#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;
    }

我的子服务器代码如下:

#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;
    }

我现在停留了很长一段时间,我似乎无法弄清问题是什么。任何帮助都将非常感谢!

1 个答案:

答案 0 :(得分:1)

如果没有pthread_join(),您的服务器例程会创建新线程,传入套接字文件描述符,然后立即继续并关闭新创建的套接字。

如果你创建多个线程,那么你需要做一些事情,比如将线程id存储在一个数组中,然后在它们之外连接它们。

最后一件事 - 你真的想将相同的套接字描述符传递给每个线程吗?如果你能建议我获得一份Unix网络编程,第1卷:套接字网络API(第3版),它将提供有关如何创建客户端/服务器应用程序的大量信息。