2015-10-28 2 views
1

У меня есть следующий отрывок кода (сильно отредактированный, чтобы удалить несущественные детали), который не срабатывает при редком и конкретном множестве обстоятельств.Как обновить события epoll после epoll_wait?

struct epoll_event *events = calloc(MAXEVENTS+1, sizeof(struct epoll_event)); 
struct sockaddr_in in_addr; 
socklen_t in_len = sizeof in_addr; 

while(1) 
    { 
    int n = epoll_wait(efd,events, MAXEVENTS, -1); 
    for(int i=0; i<n; i++) 
    { 
    struct epoll_event *evI = &events[i]; 
    uint64 u64 = evI->data.u64; 
    int type = u64>>32, fd=u64, fdx = fd; 

    if(type == -1) 
     { 
     while((fd = accept4(fdx, &in_addr, &in_len, SOCK_NONBLOCK|SOCK_CLOEXEC))>-1) 
     { 
     setNew_Connection(efd, fd); 
     storeAddrPort(fd, &in_addr, &in_len); 
     } 
     } 
    else 
     { 
     if(evI->events&(EPOLLERR|EPOLLHUP|EPOLLRDHUP)){closeConnection(fd);} 
     if(evI->events&EPOLLOUT) //process out data stuff 
     else if(evI->events&EPOLLIN) //process in data stuff and possibly close a different connection. 
     } 
    } 
    } 

слушающих сокетов различаются по -1 в верхней части evI->data.u64

setNew_Connection делает к Epoll т.д.

EPOLLET используется обычный прием такие вещи, как добавление нового сокета.

Теперь все работает прекрасно за исключением следующих обстоятельств он не потому, что events обновляется только в epoll_wait так укупорочное соединение не влияет на n события, пока после возвращения к началу цикла while(1).

  1. epoll_wait разблокирован с 3 событиями в очереди событий в таблице событий.
  2. Первое событие (n = 0) - это входящие данные, после которых код решает закрыть соединение (например, дескриптор файла 8), поскольку он больше не нужен.
  3. Второе событие (n = 1) - это новое новое соединение. accept4 назначает fd: 8, поскольку он недавно стал доступен. setNew_Connection добавляет его в список epoll.
  4. Третье событие - это входящие данные для соединения, закрытого на этапе 2. i.e fd: 8, но оно больше недействительно, поскольку исходное соединение fd: 8 было закрыто, а текущий fd: 8 - для другого соединения.

Надеюсь, я правильно объяснил проблему. Проблема в том, что события в очереди в таблице events не обновляются, когда соединение закрывается до тех пор, пока код не вернется к epoll_wait. Как я могу кодировать эту проблему?

+1

Вы можете отметить соединение будет закрыто, и сделать петлю закрытия после того, как обработчик событий. –

ответ

0

Орел дал мне ответ, но я думал, что опубликую полное решение кода. Вместо

close(fd)

Я использую

shutdown(fd,SHUT_RDWR); 
FDS[FDSL++] = fd; 

В shutdown предотвращает больше данных чтения или записи, но фактически не закрывает сокет. FDS[FDSL++] = fd; хранит ФД, так что позже после того, как русские события сделаны, она может быть закрыта с while(FDSL)close(FDS[--FDSL];

int FDS[MAXEVENTS],FDSL=0; 

struct epoll_event *events = calloc(MAXEVENTS+1, sizeof(struct epoll_event)); 
struct sockaddr_in in_addr; 
socklen_t in_len = sizeof in_addr; 

while(1) 
    { 
    int n = epoll_wait(efd,events, MAXEVENTS, -1); 
    for(int i=0; i<n; i++) 
    { 
    struct epoll_event *evI = &events[i]; 
    uint64 u64 = evI->data.u64; 
    int type = u64>>32, fd=u64, fdx = fd; 

    if(type == -1) 
     { 
     while((fd = accept4(fdx, &in_addr, &in_len, SOCK_NONBLOCK|SOCK_CLOEXEC))>-1) 
     { 
     setNew_Connection(efd, fd); 
     storeAddrPort(fd, &in_addr, &in_len); 
     } 
     } 
    else 
     { 
     if(evI->events&(EPOLLERR|EPOLLHUP|EPOLLRDHUP)){closeConnection(fd);} 
     if(evI->events&EPOLLOUT) //process out data stuff 
     else if(evI->events&EPOLLIN) //process in data stuff and possibly close a different connection. 
     } 
    } 

    while(FDSL)close(FDS[--FDSL]; 
    } 
Смежные вопросы