ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux – EBADF在epoll_wait之后的recv

2019-07-26 12:51:09  阅读:321  来源: 互联网

标签:epoll recv linux


我有一个以下问题:我有一个接收连接的epoll代码:

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);
            }


        }
    }

当我收到输入连接时,我试图读取所有buff数据:

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;
};

在accept_request函数内.但有时我在调试输出中得到以下内容:

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

这意味着有人先连接而不是断开连接,当他再次尝试连接时,recv返回EBADF.我做错了什么?请帮我.

附:在EPOLLRDHUP我只是关闭文件描述符. epoll man说没关系,因为epoll会自动从epoll_wait队列中删除关闭的fd.

解决方法:

当远程主机关闭套接字时,epoll()报告文件描述符的HUP和EPOLLIN.

首先检查EPOLLRDHUP,然后关闭套接字;然后你检查EPOLLIN,找到它,并尝试调用recv().由于套接字已关闭,文件描述符不再有效,并且您获得EBADF(已关闭的套接字从epoll集中删除,因此后续的epoll_wait()调用将不会返回它;但对于epoll_wait()已经回来太晚了 – EPOLLIN已经在你的活动中等待了[i].

调用disconnectDriver()后,您需要停止检查事件(如果它关闭了文件描述符):

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

标签:epoll,recv,linux
来源: https://codeday.me/bug/20190726/1544161.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有