3 Stimmen

EBADF während recv nach epoll_wait

Ich habe folgendes Problem: Ich habe einen Epoll-Code, der Verbindungen empfängt:

while (1) {
    int nfds = epoll_wait(epollfd, events, 4096, -1);
    if (nfds == -1) {
        if (errno == EINTR)
            continue;
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < nfds; i++) {
        if (events[i].data.fd == server_sock) {
            client_sock = accept(server_sock,
                         (struct sockaddr *)&client_name,
                         (socklen_t *)(&client_name_len));

        if (client_sock == -1) //server overloaded
            continue;

        ev.events = EPOLLIN | EPOLLERR;

#ifdef CORE_NONBLOCKING_SOCKETS
        Arch::set_nonblocking(client_sock);
        ev.events |= EPOLLET; //input data and connection closing
#endif

#ifdef EPOLLRDHUP
        ev.events |= EPOLLRDHUP ;//
#else
        //for old libraries
        ev.events |= EPOLLHUP;//
#endif

        ev.data.fd = client_sock;

        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, client_sock, &ev) == -1) {
            perror("epoll_ctl: client_socket");
            exit(EXIT_FAILURE);
        }

        accept_request(client_sock);

        } else {

#ifdef EPOLLRDHUP
            if (events[i].events & EPOLLRDHUP) {
                std::cout << "EPOLLRDHUP on " << events[i].data.fd << std::endl;
                listener->disconnectDriver(events[i].data.fd);
            }
#else
            if (events[i].events & EPOLLHUP) {
                std::cout << "EPOLLHUP on " << events[i].data.fd << std::endl;
                listener->disconnectDriver(events[i].data.fd);
            }
#endif
            if (events[i].events & EPOLLIN) {
                std::cout << "debug EPOLLIN on " << events[i].data.fd << std::endl;
                accept_request(events[i].data.fd);
            }

            if (events[i].events & EPOLLERR) {
                std::cout << "debug EPOLLERR on " << events[i].data.fd << std::endl;
                listener->disconnectDriver(events[i].data.fd);
            }

        }
    }

Wenn ich eine Eingangsverbindung erhalte, versuche ich, alle Buff-Daten zu lesen:

void get_all_buf(int sock, std::string & inStr) {
int n = 1;
int total = 0;

char c;
char temp[1024*1024]; 

bzero(temp, sizeof(temp));

do {
#ifdef CORE_NONBLOCKING_SOCKETS
    timespec time_to_wait;
    time_to_wait.tv_nsec = 10000000;
    time_to_wait.tv_sec = 0;
    timespec tm;

    time_t begin = time(NULL);
    do {
#endif

        n = recv(sock, &temp[total], sizeof(temp), 0);

#ifdef CORE_NONBLOCKING_SOCKETS
        nanosleep(&time_to_wait, &tm); 
        time_t end = time(NULL); 
        if ((end - begin) > MAX_CLIENT_TIME) {
            inStr = std::string();
            return;
        }
    } while (n < 0 && errno == EAGAIN); //nonblocking sockets in edge-triggered mode
#endif

    if (n > 0) {
        total += n;
    } else if (n == 0) {
        //TODO: error handling
        //debug
        std::cout << "possibly no one byte was received" << std::endl;
        break;
    } else if (n < 0) {
        //TODO: error handling
        //debug
        std::cout << "error while receiving data" << std::endl;
        if (errno == EBADF) {
            std::cout << "recv returns with EBADF: " << strerror(errno) << std::endl;
        } else if (errno == EFAULT) {
            std::cout << "recv returns with EFAULT: " << strerror(errno) << std::endl;
        } else if (errno == EINTR) {
            std::cout << "recv returns with EINTR: " << strerror(errno) << std::endl;
        } else if (errno == EINVAL) {
            std::cout << "recv returns with EINVAL: " << strerror(errno) << std::endl;
        }
        //end debug
        break;
    }

} while (!strstr(temp, "</packet>")); 
inStr = temp;
};

en accept_request Funktion. aber manchmal erhalte ich folgendes in meiner Debug-Ausgabe:

packet type='connect'
size of vector<Driver> in getDriversWithMoney is 1
epoll_wait detected activity of 164 counter i = 0 nfds = 1
EPOLLRDHUP on 164
disconnectDriver (fd = 164)
driver 1 disconnected
debug EPOLLIN on 164
error while receiving data
recv returns with EBADF: Invalid file descriptor

was bedeutet, dass jemand zuerst verbunden war, dann die Verbindung unterbrochen wurde und er nun versucht, sich erneut zu verbinden recv gibt zurück. EBADF . was habe ich falsch gemacht? bitte helfen Sie mir.

P.S. auf EPOLLRDHUP Ich schließe einfach den Dateideskriptor. epoll Der Mann sagt, es sei in Ordnung, weil epoll entfernt die geschlossene fd aus epoll_wait Warteschlange selbst.

9voto

caf Punkte 224189

Wenn der entfernte Host den Socket schließt, epoll() meldet sowohl eine HUP und ein EPOLLIN für den Dateideskriptor.

Sie prüfen auf EPOLLRDHUP und schließen Sie die Buchse; dann prüfen Sie, ob EPOLLIN finden Sie auch das und versuchen Sie, die recv() . Da der Socket geschlossen wurde, ist der Dateideskriptor nicht mehr gültig, und Sie erhalten EBADF (die geschlossene Buchse wird aus dem epoll gesetzt, also nachfolgend epoll_wait() Anrufe werden es nicht zurückgeben; aber für die epoll_wait() der bereits zurückgekehrt ist, ist es zu spät - die EPOLLIN wartet bereits in Ihrem events[i] .

Sie müssen aufhören, nach Ereignissen zu suchen, nachdem Sie die disconnectDriver() (wenn es den Dateideskriptor geschlossen hat):

        if (events[i].events & EPOLLRDHUP) {
            std::cout << "EPOLLRDHUP on " << events[i].data.fd << std::endl;
            listener->disconnectDriver(events[i].data.fd);
            continue;
        }

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X