epoll架构问题与瓶颈问题

发布于 2024-11-17 00:32:29 字数 2703 浏览 3 评论 0原文

while(m_severRun){

    printf("ServerManager::eventAcceptLoop, epoll_wait\n");
    int event_cnt = epoll_wait(m_epfd, m_events, EPOLL_SIZE, -1);
    if(event_cnt == -1){
        perror("epoll_wait error \n");
        break;
    }

    for(int i=0; i<event_cnt; i++){

        SocketClient *conn = reinterpret_cast<SocketClient *>(m_events[i].data.ptr);


        if(conn->getFd() == m_serverSocket->getFd()){

            printf("ServerManager::eventAcceptLoop, A Client has been connected \n");

            struct sockaddr_in clnt_adr;
            socklen_t adr_sz = sizeof(clnt_adr);
            int clnt_sock = accept(m_serverSocket->getFd(), (struct sockaddr*)&clnt_adr, &adr_sz);

            SocketClient* client = new SocketClient(clnt_sock);
            if(!addClient(client))
                break;
        }
        else{

            if(m_events[i].events & EPOLLRDHUP){
                printf("ServerManager::eventAcceptLoop, EPOLLRDHUP \n");
                removeClient(conn);
                close(conn->getFd());
                continue;
            }

            if(m_events[i].events & EPOLLIN){

                printf("ServerManager::eventAcceptLoop, EPOLLIN \n");
                int recv = conn->recv();

                if(recv <= 0){
                    removeClient(conn);
                    close(conn->getFd());
                }
                else{
                    printf("ServerManager::eventAcceptLoop, A message has been received \n");
                    vector<char> data = conn->getData();
                    addWork(conn, data);
                }
            }

            if(m_events[i].events & EPOLLERR)
                printf("ServerManager::eventAcceptLoop, EPOLLERR \n");
        }
    }//for loop end
}//while loop end

我正在研究网络编程(tcp)并且我有这段代码。这是我第一次使用 epoll,所以我不确定这个设计是否正确。另外,我正在使用线程池(5 个子线程),每当我从 epoll 读取数据时,我都会将其放入线程池的队列中。问题是在读取函数中我可以看到瓶颈问题。

在 read 函数中,它调用 ObserveSocket

int SocketClient::ObserveSock(int sock, int timeout){

    printf("SocketClient::ObserveSock called\n");

    fd_set reads;
    int fd_max;
    struct timeval _timeout;

    FD_ZERO(&reads);
    FD_SET(sock, &reads);
    fd_max = sock + 1;

    _timeout.tv_sec = timeout;
    _timeout.tv_usec = 0;

    return select(fd_max, &reads, 0, 0, &_timeout);
}

它监视套接字,如果在一定时间内没有信号,则返回 0 以关闭套接字。我想我需要这段代码来检测意外的用户断开连接或数据损坏(客户端发送了 100 个字节,但服务器收到了 90 个字节,然后服务器将等待最后 10 个字节,该字节不会到达)。

如果你们能告诉我如何解决瓶颈问题和任何架构问题,我将非常感激。

我还将寻找任何使用 epoll 并详细介绍异常处理的好教程。

提前致谢。

编辑

recv()函数内部它只调用read函数,在我读之前我调用ObserveSocket

while(m_severRun){

    printf("ServerManager::eventAcceptLoop, epoll_wait\n");
    int event_cnt = epoll_wait(m_epfd, m_events, EPOLL_SIZE, -1);
    if(event_cnt == -1){
        perror("epoll_wait error \n");
        break;
    }

    for(int i=0; i<event_cnt; i++){

        SocketClient *conn = reinterpret_cast<SocketClient *>(m_events[i].data.ptr);


        if(conn->getFd() == m_serverSocket->getFd()){

            printf("ServerManager::eventAcceptLoop, A Client has been connected \n");

            struct sockaddr_in clnt_adr;
            socklen_t adr_sz = sizeof(clnt_adr);
            int clnt_sock = accept(m_serverSocket->getFd(), (struct sockaddr*)&clnt_adr, &adr_sz);

            SocketClient* client = new SocketClient(clnt_sock);
            if(!addClient(client))
                break;
        }
        else{

            if(m_events[i].events & EPOLLRDHUP){
                printf("ServerManager::eventAcceptLoop, EPOLLRDHUP \n");
                removeClient(conn);
                close(conn->getFd());
                continue;
            }

            if(m_events[i].events & EPOLLIN){

                printf("ServerManager::eventAcceptLoop, EPOLLIN \n");
                int recv = conn->recv();

                if(recv <= 0){
                    removeClient(conn);
                    close(conn->getFd());
                }
                else{
                    printf("ServerManager::eventAcceptLoop, A message has been received \n");
                    vector<char> data = conn->getData();
                    addWork(conn, data);
                }
            }

            if(m_events[i].events & EPOLLERR)
                printf("ServerManager::eventAcceptLoop, EPOLLERR \n");
        }
    }//for loop end
}//while loop end

I am working on a network programming(tcp) and I have this code. This is my first time using epoll so I am not sure this design is correct. Also, I am using a thread pool (5 child threads) and whenever I read data from epoll I put that on the queue in the thread pool. The problem is that in the read function I can see the bottle neck problem.

In the read function, it calls ObserveSocket

int SocketClient::ObserveSock(int sock, int timeout){

    printf("SocketClient::ObserveSock called\n");

    fd_set reads;
    int fd_max;
    struct timeval _timeout;

    FD_ZERO(&reads);
    FD_SET(sock, &reads);
    fd_max = sock + 1;

    _timeout.tv_sec = timeout;
    _timeout.tv_usec = 0;

    return select(fd_max, &reads, 0, 0, &_timeout);
}

It watches the socket and if there is no signal for a certain amount of time then it returns 0 to close the socket. I thought I need this code to detect unexpected user disconnection or data corruption (client sent 100 bytes but server received 90 bytes then the server will wait for the last 10 bytes which won't arrive).

I will be very appreciated if you guys can tell me how I can fix the bottle neck problem and any architecture issues on this.

I will also look for any good tutorial that using epoll and covers exception handling in detail.

Thanks in advance.

EDIT

Inside of recv() function it just calls read function and before I read I call the ObserveSocket

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笔落惊风雨 2024-11-24 00:32:29

它监视套接字,如果有
一定时间内无信号
然后返回 0 来关闭套接字。

为什么?

我想我需要这个代码来检测
意外的用户断开连接或数据
损坏(客户端发送了 100 个字节,但
服务器收到 90 个字节然后
服务器将等待最后 10 个字节
不会到达)。

你不知道。您将收到另一个读取事件,其中读取将返回 0 指示 EOS,或者错误事件。

如果您想实现不活动超时,则必须在主选择循环中实现它。也就是说,跟踪每个套接字的最后活动时间,如果时间太长,则关闭套接字或执行任何您必须执行的操作。在再次迭代并调用 select() 之前,将此测试放在 select() 循环的底部。

目前,每个读取事件都会在超时时间内阻塞所有其他 select() 事件。所以你的整个服务器都被封锁了。

It watches the socket and if there is
no signal for a certain amount of time
then it returns 0 to close the socket.

Why?

I thought I need this code to detectever
unexpected user disconnection or data
corruption (client sent 100 bytes but
server received 90 bytes then the
server will wait for the last 10 bytes
which won't arrive).

You don't. You will get another read event where the read will return 0 indicating EOS, or an error event.

If you want to implement an inactivity timeout you have to implement it in the main select loop. That is, keep track of the last activity time for each socket, and if it gets too long close the socket or do whatever you have to do. Put this testing at the bottom of the select() loop, before you iterate and call select() again.

At the moment every read event is blocking all other select() events for the timeout duration. So your entire server is blocked.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文