Несколько сокетов UDP с использованием epoll - невозможно получить данные

Я пытаюсь получить данные из нескольких сокетов UDP, используя epoll. Это тестовая программа, у нее нет точного количества сокетов. (Для целей тестирования установлено значение 50.) Приведенная ниже программа не получает никаких данных и застревает в epoll_wait(), так как я дал -1 ей бесконечно ждет, пока не получит данные. Но не получает.

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

#define MAX_CON (50)
typedef struct UDPMessage
{
  unsigned short hdr;
  unsigned short CC1;
  unsigned short CC2;
  unsigned char  data[1472];
  unsigned short CC3;
} UDPPacket;

static struct epoll_event *events;
int create_sockets(unsigned int port);

int create_sockets(unsigned int port)
{
        int sock, flag = 1;
        struct sockaddr_in sock_name;

        /* Create a datagram socket*/
        sock = socket(PF_INET, SOCK_DGRAM, 0);
        /* Setting the socket to non blocking*/
        fcntl(sock, F_SETFL, O_NONBLOCK);

        if (sock < 0)
        {
                perror("socket");
                exit(EXIT_FAILURE);
        }
        /* Set the reuse flag. */
        if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0)
        {
                perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
                exit(EXIT_FAILURE);
        }
        /* Give the socket a name. */
        sock_name.sin_family = AF_INET;
        sock_name.sin_port = htons(port);
        sock_name.sin_addr.s_addr = htonl(INADDR_ANY);
        if (bind(sock,(struct sockaddr *) &sock_name, sizeof(sock_name)) < 0)
        {
                perror("bind");
                exit(EXIT_FAILURE);
        }
        return sock;
}

int main(int argc, char *argv[])
{
        fd_set master;
        fd_set read_fds;
        struct sockaddr_in serveraddr;
        struct sockaddr_in clientaddr;
        int fdmax=0;
        int newfd;
        int nbytes;
        int epfd = -1;
        int res = -1;
        struct epoll_event ev;
        int i=0;
        int index = 0;
        int client_fd = -1;

        int SnumOfConnection = 0;

        UDPPacket UDPPacket_obj;
        struct sockaddr_in client_sockaddr_in;
        struct sockaddr_in server_sockaddr_in;

        int sockfd[12]={0}; 
        int PORTS[12] = { 10011,10012,10013,10021,10022,10023,10031,10032,10033,10041,10042,10043}; //TEST only 12 ports
        int port_index=0;
        int sockaddr_in_length=0;

        printf("In main\n");

        /* Create sockets with the above list of ports */
        for( port_index=0;port_index<12;port_index++)
        {
                sockfd[port_index]=create_sockets(PORTS[port_index]);
                if(sockfd[port_index] > fdmax)
                        fdmax = sockfd[port_index];
        }
        printf("after soc creation\n");

        sockaddr_in_length = sizeof(struct sockaddr_in);

        events = calloc(MAX_CON, sizeof(struct epoll_event));
        if ((epfd = epoll_create(MAX_CON)) == -1)   /* epoll_create */
        {
                perror("epoll_create");
                exit(1);
        }
        ev.events = EPOLLIN;
        ev.data.fd = fdmax;

        for( port_index=0;port_index<12;port_index++)
        {
            if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[port_index], &ev) < 0)   /* epoll_ctl */
            {
                  perror("epoll_ctl");
                  exit(1);
            }
         }

         while(1)
        {
                printf("Before epoll_wait\n");
                res = epoll_wait(epfd, events, MAX_CON, -1);  /* epoll_wait */
                printf("After epoll_wait\n");
                client_fd = events[index].data.fd;

                for (index = 0; index < MAX_CON; index++)
                {
                        printf("start\n");
                        if (events[index].events & EPOLLHUP)
                        {
                                if (epoll_ctl(epfd, EPOLL_CTL_DEL, client_fd, &ev) < 0) {
                                        perror("epoll_ctl");
                                }
                                close(client_fd);
                                break;
                        }
                        printf("before EPOLLIN check\n");
                        if (events[index].events & EPOLLIN)  {
                                if((nbytes = recvfrom(client_fd,&UDPPacket_obj,sizeof(UDPPacket),0,
                                                                (struct sockaddr *)&client_sockaddr_in,
                                                                &sockaddr_in_length)) <=0)

                                {
                                        if(nbytes == 0) {
                                                printf("socket %d hung up\n", client_fd);
                                        }
                                        else {
                                                printf("recv() error lol! %d", client_fd);
                                                perror("");
                                        }

                                        if (epoll_ctl(epfd, EPOLL_CTL_DEL, client_fd, &ev) < 0) {
                                                perror("epoll_ctl");
                                        }
                                        //close(client_fd);
                                }
                                printf("Data recv=%s\n",UDPPacket_obj.data);
                        }
                }
        } //end of while
        return 0;
}

person m4n07    schedule 26.04.2013    source источник


Ответы (2)


Вы ожидаете событий только в одном сокете, в fdmax.

Вам нужно добавить все сокеты, которые вы хотите опросить.

person Some programmer dude    schedule 26.04.2013
comment
@ m4n07 Вам нужно сделать это после создания дескриптора epoll, а также, конечно, использовать правильно инициализированную структуру epoll_event. Не уверен, что вам нужно по одному на сокет. - person Some programmer dude; 26.04.2013
comment
Спасибо, я обновил код. Теперь цикл продолжается без получения данных. - person m4n07; 26.04.2013
comment
@ m4n07 Вы все еще забыли установить ev.data.fd перед вызовом epoll_ctl. Вам возможно также потребуется использовать уникальные структуры этого (я не уверен в этом), поэтому массив и для него тоже. - person Some programmer dude; 26.04.2013

Это очень старая тема.

Но в цикле while(1) строка:

client_fd = events[index].data.fd;

точно такой же:

client_fd = fdmax ;

Быть более ясным:

(A) Есть fd, который вы хотите опросить. Это тот, который вы передали в команде

epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[port_index], &ev)

Опрашиваемый fd — это sockfd[port_index]

(B) И есть fd, который вы хотите протестировать в возвращаемой структуре события. В вашем коде вы получаете доступ к нему в строке:

client_fd = events[index].data.fd;

Этот fd может быть не таким же опрашиваемым. Возвращенный fd находится в структуре события, которую вы передали в epoll_ctl:

ev.data.fd = fdmax;
:
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd[port_index], &ev)

Возвращенный fd находится внутри de ev. Даже если вы получаете событие в другом сокете, структура события, которую вы получаете, имеет fd_max в event.data.fd.

Итак, когда вы выполняете:

client_fd = events[index].data.fd;

Вы всегда получаете fd_max.

person João Monteiro    schedule 25.08.2017
comment
Спасибо. Я посмотрю, когда время позволит. - person m4n07; 25.10.2017