0

我正在实现一个迷你 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;
    }

我现在被困了很长一段时间,我似乎无法弄清楚问题是什么。任何帮助将不胜感激!

4

1 回答 1

1

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

如果您创建多个线程,那么您需要执行一些操作,例如将线程 ID 存储在一个数组中,然后在创建它们的循环之外加入它们。

最后一件事——你真的是想将相同的套接字描述符传递给每个线程吗?如果可以的话,我建议您获取一份 Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition),它将提供有关如何创建客户端/服务器应用程序的大量信息。

于 2014-10-21T14:47:48.867 回答