recvfrom() выдает ошибку дескриптора файла при использовании в потоке POSIX в C
Я реализую мини-интерфейс типа сокета YouTube. Проблема возникает при получении данных от моих субсерверов в поточном main_server, который может легко обрабатывать несколько субсерверов. Если я присоединюсь к потоку через pthread_join после создания потока в main, вызов потока будет успешным, и данные будут получены с субсервера, но это технически разрушает весь смысл создания многопоточной среды субсервера. Если я не присоединяюсь к ветке, вот к чему приходит ошибка:
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 ответ
Без pthread_join() ваша серверная процедура создает ваш новый поток, передавая дескриптор файла сокета, а затем быстро продолжает и закрывает вновь созданный сокет.
Если вы создаете несколько потоков, вам нужно сделать что-то вроде сохранения идентификаторов потоков в массиве и последующего присоединения к ним вне цикла, который их создает.
И последнее: вы действительно хотите передать один и тот же дескриптор сокета в каждый поток? Если вы можете мне предложить получить копию Сетевого программирования Unix, Том 1: Сетевой API-интерфейс Sockets (3-е издание), в котором будет много информации о том, как создать клиент-серверное приложение.