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 を呼び出します

4

1 に答える 1

2

ソケットを監視し、一定時間信号がない場合は 0 を返してソケットを閉じます。

なんで?

予期しないユーザーの切断やデータの破損を検出するには、このコードが必要だと思いました (クライアントは 100 バイトを送信しましたが、サーバーは 90 バイトを受信し、サーバーは最後の 10 バイトが到着しないのを待ちます)。

あなたはそうしない。読み取りが EOS を示す 0 を返す別の読み取りイベント、またはエラー イベントを取得します。

非アクティブ タイムアウトを実装する場合は、メインの選択ループに実装する必要があります。つまり、各ソケットの最後のアクティビティ時間を追跡し、時間がかかりすぎる場合は、ソケットを閉じるか、必要なことを行います。反復して select() を再度呼び出す前に、このテストを select() ループの最後に配置します。

現在、すべての読み取りイベントは、タイムアウト期間中、他のすべての select() イベントをブロックしています。したがって、サーバー全体がブロックされます。

于 2011-06-23T04:27:57.397 に答える