Ошибка неправильного файлового дескриптора при создании параллельного сервера в клиент-серверном приложении (UDP)

#c #sockets #unix

#c #сокеты #unix

Вопрос:

Я создаю клиент-серверное приложение с udp на параллельном сервере, и у меня возникают некоторые проблемы с отправкой информации на сервер.

Вот код для сервера:

 #define SERV_UDP_PORT   6777

int main() {

int sockfd, newsockfd, clilen, n, pid_hijo;
struct sockaddr_in cli_addr, serv_addr ;
char host_name[200], buffer[1024];

if ((sockfd = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP)) < 0){
   perror("server: can't open datagram socket");
   exit(-1);
} /* if */


serv_addr.sin_family = AF_INET ;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY) ;
serv_addr.sin_port = htons(SERV_UDP_PORT);

if (bind(sockfd, (struct sockaddr *) amp;serv_addr, sizeof(serv_addr)) <0) {
    perror("server: can't bind local address") ;
    exit(-1);
} /* if */


for (;;) {
    // Create the new process for the concurrente server
    if ((pid_hijo=fork()) == 0) {
        servidor_hijo(sockfd);
        close(sockfd);
        exit(0);
    }
    else {
        close(sockfd);
        while (wait((int *)0) != pid_hijo);
    }
}
}

int servidor_hijo(int sockfd) {

int n, clilen;
char buffer[1024];
struct sockaddr_in cli_addr;


// Inicializamos los buffers
clilen = sizeof(cli_addr) ;
bzero((char *)amp;cli_addr,clilen); /* debe inicializarse cli_addr antes del recvfrom */
bzero(buffer, sizeof(buffer));


if ((n=recvfrom(sockfd, buffer, sizeof(buffer),0, (struct sockaddr *)amp;cli_addr,amp;clilen)) <0) {
    perror("secho: error en funcion recvfrom");
    exit(-1);
} /* if */


printf("nn%s (%d bytes)n",buffer,n);

if ((n=sendto(sockfd, buffer, strlen(buffer),0, (struct sockaddr *)amp;cli_addr,clilen)) <0) {
    perror("secho: Error en funcion sendto");
    exit(-1);
}
}
  

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

 /* Cliente de ECO sobre UDP*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define SERV_UDP_PORT   6777

main() {
    int sockfd, n, clilen;
    struct sockaddr_in serv_addr, cli_addr ;
    char serv_host_addr[30], buffer[1024];

    printf("Dirección IP del servidor (a.b.c.d) => ");
    gets(serv_host_addr);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("client: can't open datagram socket") ;
        return -1;
    }


    bzero((char *)amp;cli_addr,sizeof(cli_addr)); /* puerto cero */
    cli_addr.sin_family = AF_INET ;

    if (bind(sockfd, (struct sockaddr *) amp;cli_addr,sizeof(cli_addr)) < 0) {
        perror("client: can't bind a port");
        exit(-1);
    } /* if */

    serv_addr.sin_family = AF_INET ;
    inet_pton(AF_INET,serv_host_addr,amp;serv_addr.sin_addr);
    serv_addr.sin_port = htons(SERV_UDP_PORT) ;


    printf("Bienvenido al Servicio de ECO ==> "); 
    gets(buffer);

    clilen=sizeof(serv_addr);
    if ((n=sendto(sockfd, buffer,strlen(buffer),0, (struct sockaddr *)amp;serv_addr,clilen)) <0) {
        perror("cecho: error en funcion sendto");
        exit(-1);
    } /* if */

    printf("cecho: envie %d bytesn",n);

    bzero(buffer,sizeof(buffer));
    clilen = sizeof(serv_addr);

    if ((n=recvfrom(sockfd,buffer,sizeof(buffer),0, (struct sockaddr*)amp;serv_addr,amp;clilen)) < 0) {
        perror("cecho: error en funcion recvfrom");
        exit(-1);
    } /* if */
    printf("ECO> %sn",buffer);
    close(sockfd);
    }
  

Функция servidor_hijo — это то, что делает сервер параллельным для ответа на другой запрос…

Проблема в том… Когда я запускаю клиентское приложение, оно отправляет пакет серверному приложению, но сервер не отправляет ответ и выводит на экран сообщение об ошибке, в котором говорится, что это была «Ошибка неправильного файлового дескриптора».

Не могли бы вы помочь мне с этим?

Спасибо вам всем!!

Комментарии:

1. Сначала вы должны открыть сокет с: udp_socket = socket(AF_INET, SOCK_DGRAM, 0); Затем попытайтесь точно определить, в какой момент генерируется ошибка неправильного файлового дескриптора. Это внутри функции servidor_hijo? Где именно?

2. Я сделал это … : (не знаю, что не так : (

3. ошибка генерируется в функции recvfrom.

4. Что бы ни случилось, вы должны заменить exit(-1) на exit(EXIT_FAILURE) . Во многих системах Unix возможный диапазон значений для кодов состояния возврата в командной строке равен 0-255, где 0 означает успех, а 1 является типичным значением для сбоя (вы, вероятно, обнаружите, что EXIT_FAILURE означает 1). Выход с -1 приведет к переполнению, и ваша оболочка увидит код возврата как 255, что просто сбивает с толку.

Ответ №1:

Попробуйте это: (В противном случае мне пришлось бы прочитать о fork и fd) В else of the fork удалите close, иначе сокет закрывается, так как другой процесс хочет отправить данные обратно.

hth

Марио

Комментарии:

1. Спасибо! однако будьте осторожны, я не уверен (и не нашел быстрого ответа), действительно ли это хорошая идея. При форке fd используются dup(), поэтому он также должен работать.

Ответ №2:

Вы вызываете bind(), а затем fork(). У вас не может быть двух процессов и двух сокетов, привязанных к одному и тому же порту.

Я предлагаю вам получить пакет, а затем fork () обработать его.