2016-05-25 2 views
0

Я пытаюсь написать простое приложение чата, в котором клиент получает строку с сервера и отправляет новое сообщение, которое будет доставлено к следующему подключению клиента. Я новичок в программировании сокетов, и я действительно не могу понять, почему эта ошибка возникает. После того, как клиент отправляет свой буфер, сервер уведомляет об ошибке accept() (возврат -1) и деструктор файла. Вот код, работающий на сервере:bad file descriptor: error on accept()

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <time.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

void error(char *msg) { 
    perror(msg); 
    exit(1); 
} 

int main (int argc, char *argv[]) { 

    if (argc < 2) { 
     error("ERROR, no port provided\n"); 
    } 

    int sockfd; 
    struct sockaddr_in serv_addr, cli_addr; 
    int cli_len, portno; 
    char message[256]; 
    pid_t pid; 
    int n; 

    portno = atoi(argv[1]); 
    bzero((char*)&serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    n = bind (sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    if (n < 0) { 
     error("ERROR on binding\n"); 
    } 

    listen(sockfd, 5); 

    do { 
     cli_len = sizeof(cli_addr); 

     int newsockfd; 
     newsockfd = accept(sockfd,(struct sockaddr*)&cli_addr,(socklen_t *)&cli_len); 
     if (newsockfd < 0) { 
      printf("%i", newsockfd); 
      error("ERROR on accept\n"); 

     } 

     pid = fork(); 
     if(pid == 0) { 

      close(sockfd); 
      sockfd = -1; 

      n = send(newsockfd, message, strlen(message), 0); 
      if (n < 0) error("ERROR sending\n"); 

      bzero(message, 256); 

      n = recv(newsockfd, message, 256, 0); 
      if (n < 0) error("ERROR receiving\n"); 

      close(newsockfd); 
      newsockfd = -1; 

     } 

    } 
    while(1); 

    return 0; 
} 
+2

cli_len должно быть типа socklen_t, а не int. Привилегия скрывает потенциальную проблему на x86_64, где int может быть 32 бит, но другие типы size_related могут быть 64 бит. –

+1

Вы неправильно сообщаете об ошибке. Вам нужно вызвать 'perror()' или 'strerror()' * перед тем, как сделать что-то еще, что может изменить 'errno', например' printf() '. Fix, retest, ... – EJP

+2

Задача 2, ребенок должен вызывать exit, когда закончите, иначе оба ребенка и родитель будут сражаться в accept() ;-) –

ответ

1

Ребенок, раздвоенный, должен заканчиваться после read(), но это не так. Он продолжает цикл. Скорее всего, это не ваше намерение.

Затем ребенок вызывает accept(), проходя -1 в качестве дескриптора сокета. -1 не является допустимым дескриптором сокета.

accept(sockfd, ... 

Ребенок устанавливает sockfd в -1 здесь:

pid = fork(); 
    if(pid == 0) { 

     close(sockfd); 
     sockfd = -1; 

Это действительный дескриптор сокета, возвращаемый socket() переопределены, теряется.

Таким образом, ошибка, которую вы наблюдаете, не возникает из-за процесса прослушивания, а из раздвоенного ребенка.

Чтобы исправить это добавить вызов exit() внутри ребенка, как это:

 ... 
     newsockfd = -1; 
     exit(EXIT_SUCCESS); 
     } 

Это int cli_len; должно быть socklen_t cli_len;. И приведение cli_len при вызове accept() должно быть удалено. Do не слепо отбросить ошибки!

2

Если результат fork() равен нулю, что нужно сделать ваш I/O с принятой розеткой , а затем выйти из процесса. В настоящее время вы разрешаете цикл accept повторяться в дочернем процессе после закрытия прослушивающего сокета.

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