2013-02-10 2 views
0

Я работаю над внедрением многопоточного многопользовательского односерверного сокета в C C. Однако по какой-либо причине в настоящее время программа при использовании pthread_create() для создания нового потока не продвигается мимо этой строки код. Я поместил строки печати до и после этой строки кода и всех строк печати перед печатью вручную, но ни один из них после печати. Это заставляет меня поверить, что pthread_create() как-то глючит. Странная вещь об этом заключается в том, что у меня может быть 1 клиент, который подключается и успешно отправляет/получает данные с сервера, но поскольку цикл, в котором выполняется команда listen(), не продвигается, я не могу взять дополнительных клиентов. Я ценю вашу помощь в этом вопросе.Реализация Socket multithreading C

код сервера

#include <stdio.h> 
#include <stdlib.h> //for IOs 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> //for system calls 
#include <sys/socket.h> //for sockets 
#include <netinet/in.h> //for internet 
#include <pthread.h> 

void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 
void *threadFunc(int mySockFd) 
{ 
    int n; 
    char buffer[256]; 
    do 
    { 
     bzero(buffer,256); 
     n = read(mySockFd,buffer,255); 
     if (n < 0) 
     { 
      error("ERROR reading from socket"); 
     } 
     else if(strcmp(buffer, "EXIT\n") == 0) 
    { 
     printf("Exit by user\n"); 
     pthread_exit(NULL); 
    } 
    else 
    { 
     printf("Here is the message: %s\n",buffer); 
      n = write(mySockFd,"I got your message",18);    
      if (n < 0) 
      { 
       error("ERROR writing to socket"); 
      } 
     } 
    }while(n >= 0); 


}  

int main(int argc, char *argv[]) 
{ 
    int sockfd; 
    int newsockfd; 
    int portno; 
    pthread_t pth; 
    int n; /*n is the return value for the read() and write() calls; i.e. it contains  the number of characters read or written.*/ 
    int i = 0; 
    printf("after var decl"); 
socklen_t clilen; /*clilen stores the size of the address of the client. This is  needed for the accept system call.*/ 
    char buffer[256]; /*The server reads characters from the socket connection into  this buffer.*/ 
    struct sockaddr_in serv_addr; 
    struct sockaddr_in cli_addr; 
if (argc < 2) 
    { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 
sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd < 0) 
    { 
     error("ERROR opening socket"); 
    } 
bzero((char *) &serv_addr, sizeof(serv_addr)); 
portno = atoi(argv[1]); 
serv_addr.sin_family = AF_INET; 
serv_addr.sin_addr.s_addr = INADDR_ANY; 
serv_addr.sin_port = htons(portno); 
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
    { 
     error("ERROR on binding"); 
    } 
do 
    {  
     printf("before listen"); 
     listen(sockfd,5); 
     printf("after listen"); 
       clilen = sizeof(cli_addr); 
     printf("before accept"); 
     newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen); 
     printf("after accept"); 
     pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i); 
     printf("after pthread create"); 
     if (newsockfd < 0) 
     { 
      error("ERROR on accept"); 
     } 
    }while(1 == 1); 
bzero(buffer,256); 
    n = read(newsockfd,buffer,255); 
    if (n < 0) 
    { 
     error("ERROR reading from socket"); 
    } 
    printf("Here is the message: %s\n",buffer); 
if (n < 0) error("ERROR writing to socket"); 
close(newsockfd); 
    close(sockfd); 
    return 0; 

и вот код клиента

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> /*The file netdb.h defines the structure hostent, which will be  used below.*/ 
void error(const char *msg) 
{ 
    perror(msg); 
    exit(0); 
} 

int main(int argc, char *argv[]) 
{ 
int sockfd; 
int portno; 
int n; 
struct sockaddr_in serv_addr; 
struct hostent *server; 
char buffer[256]; 
if (argc < 3) 
{ 
    fprintf(stderr,"usage %s hostname port\n", argv[0]); 
    exit(0); 
} 
    portno = atoi(argv[2]); 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
if (sockfd < 0) 
{ 
    error("ERROR opening socket"); 
} 
server = gethostbyname(argv[1]); 
if (server == NULL) 
{ 
    fprintf(stderr,"ERROR, no such host\n"); 
    exit(0); 
} 
bzero((char *) &serv_addr, sizeof(serv_addr)); 
serv_addr.sin_family = AF_INET; 
bcopy((char *)server->h_addr, 
(char *)&serv_addr.sin_addr.s_addr, 
server->h_length); 
serv_addr.sin_port = htons(portno); 
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
{ 
    error("ERROR connecting"); 
} 
do 
{ 
    printf("Please enter the message: "); 
    bzero(buffer,256); 
    fgets(buffer,255,stdin); 
    n = write(sockfd,buffer,strlen(buffer)); 
    if(strcmp(buffer,"EXIT\n") == 0) 
    { 
     printf("Connection Terminated\n"); 
     break; 
    } 
    if (n < 0) 
    { 
     error("ERROR writing to socket"); 
    } 
    bzero(buffer,256); 
    n = read(sockfd,buffer,255); 
    printf("%s\n",buffer); 
    if (n < 0) 
    { 
    error("ERROR reading from socket"); 
    printf("%s\n",buffer); 
    } 

}while(1 == 1); 
close(sockfd); 
return 0; 
} 
+0

использовать отладчик и выполнить его. вместо этого используйте 'fprintf (stderr," ")'. Отсоедините новый поток. Параметры темы должны быть выделены отдельно, если это необходимо. – SparKot

+0

На вашем сервере thread_func, read() вернет 0, чтобы указать, что удаленная сторона полностью закрыла соединение. Поскольку у вас есть это сейчас, я мог бы написать подключаемого изгоняющего клиента, затем закрывается без отправки «EXIT», и ваш поток не выйдет. – selbie

+0

Ну ...он, вероятно, выйдет после последующего вызова «write». – selbie

ответ

0

Ваш серверный код не отображает PRINTF заявления надежно, потому что вы не конец строки, переданные PRINTF с a "\ n".

Измените все ваши заявления printf, чтобы включить трейлинг \ n, так что вывод будет немедленно очищен. Например.

Вместо:

printf("after pthread create"); 

ли это:

printf("after pthread create\n"); 

Repeat, фиксирующих для всех ваших PRINTF заявлений. И тогда поток программы будет более заметным, поскольку клиенты подключаются к нему.

Возможно, в вашем коде имеется около 5 или 6 других ошибок. Основной из них, который я хочу вызывать, заключается только в том, что клиент отправил 4 байта «EXIT», не означает, что поток TCP не будет фрагментировать его в «EX» и «IT» через два отдельных чтения в зависимости от состояние межтруб. Всегда записывайте свой код протокола, как если бы read/recv собирался возвращать только один символ за раз. OR просто используйте MSG_WAITALL с recv(), чтобы вы всегда читали размер куска.

4

Две ошибки:

  1. Вы бросаете слишком много, единственное место, здесь должны стать inaddr материал.
  2. Вы не слушаете свой компилятор и повышаете уровень предупреждения.

Теперь проблема (? Или, может быть только один) на самом деле это:

pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i); 

Это будет вызывать threadFunc(newsockfd) и передать результат в pthread_create. Вторая часть никогда не произойдет, потому что эта функция вызывает pthread_exit или падает с конца, не возвращая ничего, что может привести к чему-либо.

+0

Да, исправьте @Ulrich UB, передав только «threadFunc», чтобы использовать адрес функции, а затем передать новый сокет fd в качестве последнего параметра (void *) вместо этого «i» thingy (не уверен, что это такое для?). –