2013-09-07 2 views
0

Я пытаюсь создать чат-программу с использованием UDP. Я создал родительский и дочерний процесс как на клиенте, так и на сервере, чтобы получать и отправлять сообщения отдельно. Проблема в том, что сервер не может отправить. Помоги пожалуйста. Вот мой код.Не удалось отправить дочерний процесс UDP-сервера

КЛИЕНТ

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

    int main(int argc, char **argv) 
    { 
     int sockfd; 
     struct sockaddr_in servaddr; 
     socklen_t len = sizeof(servaddr); 
     char mesg[1024], rmesg[1024]; 
     pid_t pid; 

     if(argc!=2){ 
      printf("Usage: %s <ip_addr>\n",argv[0]); 
      exit(1); 
     } 

     sockfd = socket(PF_INET,SOCK_DGRAM,0); 
     bzero(&servaddr, sizeof(servaddr)); 
     servaddr.sin_family = AF_INET; 
     servaddr.sin_port = htons(54321); 
     inet_pton(AF_INET,argv[1],&servaddr.sin_addr); 

     pid = fork(); 
     if(pid == 0) { 
      printf("Type 'exit' to Exit. \n"); 
      while(1){ 
       fgets(mesg,sizeof(mesg),stdin); 
       sendto(sockfd,mesg,strlen(mesg),0,(const struct sockaddr *)&servaddr,len); 
       if(strcmp(mesg, "exit\n") == 0) 
        break; 
      } 
      close(sockfd); 
      kill(pid, SIGINT); 
      exit(0); 
     }else{ 
      while(1){ 
       memset(rmesg,0,sizeof(rmesg)); 
       if(recv(sockfd,rmesg,sizeof(rmesg),0) > 0){ 
        printf("From Server: %s", rmesg); 
       } 
      } 
     } 
     close(sockfd); 
     return 0; 
    } 

SERVER

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

    int main(int argc, char **argv) 
    { 
     int sockfd1; 
     struct sockaddr_in servaddr,cliaddr; 
     socklen_t len = sizeof(cliaddr); 
     char cli_ip[32]; 
     char mesg[1024], smesg[1024]; 
      pid_t pid1; 

     sockfd1 = socket(PF_INET,SOCK_DGRAM,0); 
     bzero(&servaddr, sizeof(servaddr)); 
     servaddr.sin_family = AF_INET; 
     servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
     servaddr.sin_port = htons(54321); 
     inet_ntop(AF_INET,(struct in_addr *) &cliaddr.sin_addr, cli_ip, sizeof(cli_ip)); 

     if (bind(sockfd1, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0){ 
      perror(NULL); 
      exit(-1); 
     } 

     pid1 = fork(); 
     if(pid1 == 0){ 
      while(1){ 
       memset(mesg,0,sizeof(mesg)); 
       if(recvfrom(sockfd1,mesg,sizeof(mesg),0,(struct sockaddr *)&cliaddr,&len) > 0){ 
        printf("From client: %s",mesg); 
       } 
      } 
     }else{ 
      printf("Type 'exit' to Exit. \n"); 
      while(1){ 
       fgets(smesg,sizeof(smesg),stdin); 
       sendto(sockfd1,smesg,strlen(smesg),0,(struct sockaddr *)&cliaddr,len); 
       if(strcmp(smesg, "exit\n") == 0) 
        break; 
      } 
      close(sockfd1); 
      kill(pid1, SIGINT); 
      exit(0); 
     } 
     return 0; 
    } 
+0

В этом коде полностью отсутствует проверка ошибок при чтении и записи и большинстве других системных вызовов! В первую очередь это плохо и неразумно, так как обнаружение ошибок - это единственная возможность реагировать на них. И, по крайней мере, это помогает во время разработки, тестирования и отладки! – alk

+0

Почему сервер вызывает 'inet_ntop' на неинициализированном' cliaddr.sin_addr'? Он также вызывает 'recvfrom()' в дочернем процессе, но родительский процесс пытается использовать этот 'cliaddr' в своем' sendto' - структура не обновляется в родительском процессе. – Barmar

ответ

1

Проблема, скорее всего, в клиенте:

while(1){ 
    if(recv(sockfd,rmesg,sizeof(rmesg),0) > 0){ 
     printf("From Server: %s", rmesg); 
    } 
} 

Вы звоните recv на несвязанной розетке. Вероятно, вы получите ошибку (возможно, ENOTCONN), которую вы игнорируете. И я считаю, что вы также видите высокий уровень использования ЦП на своих клиентах, поскольку он постоянно циклически, при каждом системном вызове.

Вместо этого вместо этого следует использовать recvfrom. В качестве альтернативы вы можете позвонить connect на сокете, даже если это SOCK_DGRAM, но это обычно не делается.

+1

, если вы не вызываете 'connect()', вам нужно вызвать 'bind()', чтобы установить локальный порт для прослушивания. – Barmar

+0

@Barmar, вам не нужен сокет для подключения к UDP. Пока он связан с портом, по которому отправитель отправляет данные, получатель сможет получить его. Конечно, сокет UDP также может вызывать connect(), как вы упомянули. –

+0

@ManojPandey Разве это не то, что я сказал? Вы, кажется, комментируете ответ, а не мой комментарий. – Barmar

0

ПОЧЕМУ У вас используется тот же сокет для сервера и клиента? Это не имеет смысла. Более простой альтернативой было бы использование двух потоков. Один поток обрабатывает серверный сокет и другой поток, обрабатывающий клиентский поток. И, конечно же, вам нужно будет иметь два сокета: один для сервера и один для клиента. Кроме того, sendto() должен иметь адрес и информацию о порте получателя.

+0

@ user2757209 Если вы используете код отдельно для клиента и сервера, почему вы делаете fork() для клиента/сервера?Вы используете потоки, чтобы справиться с этим - они более эффективны. Создание процесса с каждым клиентом очень неэффективно. –

+0

Я еще не знаю, как использовать потоки, поэтому я решил использовать fork(). Эффективность не имеет большого значения, и это всего лишь двухсторонняя коммуникационная программа. – user2757209

+0

Для текущей опции вы все равно можете использовать основной процесс для выполнения своих задач, поскольку sendto() является неблокирующим вызовом. Если вам нужно масштабировать в какой-то момент, я бы настоятельно рекомендовал потратить некоторое время на Pthreads. Создание процесса намного дороже, чем создание потоков. Это будет стоить потраченного времени, особенно когда вы пытаетесь масштабировать. –

Смежные вопросы