新连接发送数据后,epoll是否没有通知EPOLLIN事件?

时间:2018-08-17 05:05:17

标签: c++ events epoll

我在服务器程序上使用了epoll,但是遇到了一个问题。我做了一个简单的测试来重现此问题。服务器在接收客户端数据后关闭了套接字,然后客户端将重新连接服务器并继续发送数据。一段时间(约数十秒),新连接发送数据后,epoll_wait不再通知EPOLLIN事件。但是在epoll_wait超时后,我可以从新客户端的sockt fd接收数据。 epoll会丢失一些事件吗? ET和LT模式都进行了测试。

服务器代码:

#include <iostream>
#include <thread>
using namespace std;
#include <sys/epoll.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>

inline string get_time_for_ms()
{
    timeval tmval;
    gettimeofday(&tmval,nullptr);

    struct tm tml;
    localtime_r(&tmval.tv_sec,&tml);

    char buffer[30] = { 0 };
    snprintf(buffer,30,"%04d-%02d-%02d %02d:%02d:%02d:%03ld", tml.tm_year+1900, tml.tm_mon+1, tml.tm_mday, tml.tm_hour, tml.tm_min, tml.tm_sec, tmval.tv_usec/1000);

    return string(buffer);
}

int fd_=-1;
int client_fd_=-1;
int cnt=0;

void register_event(int fd,int oper)
{
    epoll_event env;
    env.data.fd=fd;
    env.events=EPOLLIN;

    epoll_ctl(fd_,oper,fd,&env);
    cout<<get_time_for_ms()<<" epoll_ctl:"<<fd<<" thread:"<<this_thread::get_id()<<endl;
}

void recv_data(int fd)
{
    while(true)
    {
        char buf[1024]={0};
        int data_len=recv(fd,buf,1024,MSG_NOSIGNAL);
        if(data_len<=0)
        {
            break;
        }
        else
        {   
            cnt+=data_len;
            cout<<get_time_for_ms()<<" epoll in recv len:"<<data_len<<",total len:"<<cnt<<endl;
        }
    }
}

void epoll_wait_handler()
{
    while(true)
    {
        const static int event_max=5;
        epoll_event envs[event_max]={0};
        int ret=epoll_wait(fd_,envs,event_max,15000);
        if(ret>0)
        {
            for(int i=0;i<ret;++i)
            {
                if(envs[i].events&EPOLLIN)
                {
                    client_fd_=-1;
                    recv_data(envs[i].data.fd);

                    register_event(envs[i].data.fd,EPOLL_CTL_DEL);
                    shutdown(envs[i].data.fd,SHUT_RDWR);
                    close(envs[i].data.fd);
                }
                else if(envs[i].events&(EPOLLERR|EPOLLHUP))
                {
                    cout<<"epoll error:"<<envs[i].data.fd<<" thread:"<<this_thread::get_id()<<endl;
                }
                else
                {
                    cout<<"epoll_wait error:........"<<envs[i].data.fd<<endl;
                    this_thread::sleep_for(chrono::seconds(120));
                }
            }
        }
        else
        {
            printf("\033[31m%s%s thread:%lu\n\033[0m",get_time_for_ms().c_str()," epoll_wait timeout",this_thread::get_id());

            this_thread::sleep_for(chrono::seconds(3));
            if(client_fd_>0)
            {
                recv_data(client_fd_);
                cout<<"recv return thread:"<<this_thread::get_id()<<endl;
                this_thread::sleep_for(chrono::seconds(30));

                shutdown(client_fd_,SHUT_RDWR);
                close(client_fd_);

                client_fd_=-1;
            }
            else
            {
                cout<<"not recv return thread:"<<this_thread::get_id()<<endl;
            }
        }
    }
}

void server_listen()
{
    int listen_fd_=socket(PF_INET,SOCK_STREAM,0);

    int opt=1;
    setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port = htons(7100);
    inet_pton(AF_INET, "0.0.0.0",&addr.sin_addr);

    if(bind(listen_fd_,(sockaddr*)&addr,sizeof(addr))==-1)
    {
        close(listen_fd_);
        cout<<"bind error"<<endl;
    }

    listen(listen_fd_,128);

    cout<<"bind success"<<endl;
    while(true)
    {
        sockaddr_in saddr;
        int ilen = sizeof(saddr);
        int soc = accept(listen_fd_, (sockaddr *)&saddr, (socklen_t*)&ilen);
        if(soc>0)
        {

            cout<<"accept new connect:"<<soc<<endl;
            int old=fcntl(soc,F_GETFL);
            int newfd=old|O_NONBLOCK;

            fcntl(soc,F_SETFL,newfd);
            client_fd_=soc;

            register_event(soc,EPOLL_CTL_ADD);
        }
    }
}

int main()
{
    fd_=epoll_create(5);

    for(int i=0;i<1;++i)
    {
        thread t{epoll_wait_handler};
        t.detach();
    }

    server_listen();
}

客户代码

#include <iostream>
#include <thread>
using namespace std;
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/time.h>

int fd_=-1;
int cnt=0;

inline string get_time_for_ms()
{
    timeval tmval;
    gettimeofday(&tmval,nullptr);

    struct tm tml;
    localtime_r(&tmval.tv_sec,&tml);

    char buffer[30] = { 0 };
    snprintf(buffer,30,"%04d-%02d-%02d %02d:%02d:%02d:%03ld", tml.tm_year+1900, tml.tm_mon+1, tml.tm_mday, tml.tm_hour, tml.tm_min, tml.tm_sec, tmval.tv_usec/1000);

    return string(buffer);
}

void send_data()
{
    const char *data="123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";
    int s_len = send(fd_,data, strlen(data),MSG_NOSIGNAL);
    if(s_len>0)
    {
        cnt+=s_len;
        cout<<get_time_for_ms()<<" send data:"<<s_len<<" total:"<<cnt<<endl;
    }
}

void connect_server(bool nw);

void recv_data()
{
    while(true)
    {
        char buf[1024]={0};
        int data_len=recv(fd_,buf,1024,MSG_NOSIGNAL);
        if(data_len<=0)
        {
            cout<<"recv error:"<<fd_<<endl;
            close(fd_);
            fd_=-1;

            connect_server(false);
        }
        else
        {   
            cout<<"recv successd:"<<buf<<endl;
        }
    }
}

void connect_server(bool nw)
{
    int fd=socket(PF_INET,SOCK_STREAM,0);

    struct sockaddr_in addr;
    addr.sin_family=AF_INET;
    addr.sin_port = htons(7100);
    inet_pton(AF_INET,"172.16.5.47",&addr.sin_addr);

    if (connect(fd, (sockaddr *)&addr, sizeof(addr))<0)
    {
        cout<<"connect error"<<endl;
        return;
    }
    fd_=fd;
    if(nw)
    {
        thread t{recv_data};
        t.detach();
    }

    send_data();
}

int main()
{
    connect_server(true);

    this_thread::sleep_for(chrono::hours(1));
}

0 个答案:

没有答案