1
votes

Lets say I am listening at multiple network ports: 80 with TCP 81-250 with UDP

This requires multiple different ways of handling inputs.
- New socket at port 80 ( add new file descriptor to epoll list )
- Read from client socket at port 80
- Read from any of the other 170 UDP ports

This are quite a lot different handles, while I would like to use epoll to only react to the ones being updated.
Is there any way epoll events can be filtered, so every event gets its needed handle, without looping through all file descriptors?

Thanks in advance,
Sinned

Example code:

int epfd = epoll_create( 10 );

int tcpFd = createTCPSocket( 80 );
registerListenEvent( epfd, tcpFd );

int udpFds[ 170 ];
for ( int i = 0; i < 170; i++ ) {
  udpSockets[ i ] = createUdpSocket( 81 + i );
  registerUdpPacketEvent( epfd, udpFds[ i ] );
}

int tcpClientFds[ 256 ];
int tcpClientId = 0;

struct epoll_event events[ 64 ];

while ( 1 ) {
  int nfds = epoll_wait( epfd, events, 64, -1 );
  for ( int i = 0; i < nfds; i++ ) {
    struct epoll_event event = events[ i ];
    int fd = event.data.fd;

    // This kind of filtering can take quite a while
    if ( fd == tcpFd ) {
      int acceptedFd = accept( tcpFd );
      registerTcpClientEvent( epfd, acceptedFd );
      tcpClientFds[ tcpClientId++ ] = acceptedFd;
    } else {
      for ( int i = 0; i < 170; i++ )
        if ( udpFds[ i ] == fd ) {
          handleUdpMessage( fd );
          return;
        }
     for ( int i = 0; i < tcpClientId; i++ ) {
       if ( tcpClientFds[ i ] == fd ) {
         handleTcpMessage( fd );
         return;
       }
     }
    }
  }
}

You can imagine going through 170 - 426 loops for every event can be quite costly. I hoped the event could be identified without this. Is this possible?

2
What do mean by being updated? You want to select events from a subset of your descriptors? - Valeri Atamaniouk

2 Answers

1
votes

epoll() tells you the exact file descriptor(s) that triggered the event(s). You don't have to hunt for them. Read the documentation for an example. epoll_wait() gives you an array of epoll_event structs, one for each satisfied file descriptor. The epoll_event struct has an fd member. You would register your individual sockets for EPOLLIN events, and then each time epoll_wait() reports satisfied events, you would read from just the reported sockets as needed.

0
votes

Like 'remy' mentioned create your own structure per socket and add it to event. When event triggered first refer your structure and start handling.

    struct epoll_event event = {0, {NULL, 0, 0, 0}};
    int s = 0;

    event.data.fd = tp->task_socket;
    event.data->ptr = tp;
    event.events = EPOLLOUT;

    assert(efd);

    s = epoll_ctl (efd, EPOLL_CTL_DEL, tp->task_socket, &event);

handling part:

case EPOLLOUT: tp = (task *)ev->data->ptr;

This tp should tell all about your sockets and handling function..