2

私は、3.6 MB/sのUDPデータグラムを受信するWindows7VisualC++サーバーアプリケーションを作成しています。recvfrom()がデータを受信するメインスレッドがあります。ソケットは非ブロッキングソケットであり、64kBの受信バッファーがあります。ソケットでデータが受信されていない場合、スレッドはsleep(1)を実行します。

私の問題は、スレッドがデュアルコアプロセッサのほぼ50%を使用していて、どうすればそれを減らすことができるかわからないことです。Wiresharkはその20%しか使用していないので、私の主な目標は同様の割合を達成することです。

あなたはなにか考えはありますか?

4

4 に答える 4

4

ポーリングする代わりに、選択のようなアプローチを使用して、データがソケットに到着するか、クライアントがシャットダウンを決定するのを待つことができます。

最初にソケットをノンブロッキングにします:

u_long nonBlocking = 0;
WSAEventSelect(sock, NULL, 0);
ioctlsocket(sock, FIONBIO, &nonBlocking);

次に、WSAWaitForMultipleEventsを使用して、データが到着するか、recv をキャンセルするまで待機します。

int32_t MyRecv(THandle sock, WSAEVENT* recvCancelEvt,
               uint8_t* buffer, uint32_t bufferBytes)
{
    int32_t bytesReceived;
    WSAEVENT evt;
    DWORD ret;
    HANDLE handles[2];

    event = WSACreateEvent();
    if (NULL == evt) {
        return -1;
    }
    if (0 != WSAEventSelect(handle->iSocket, evt, FD_READ|FD_CLOSE)) {
        WSACloseEvent(evt);
        return -1;
    }

    bytesReceived = recv(sock, (char*)buffer, bufferBytes, 0);
    if (SOCKET_ERROR==received && WSAEWOULDBLOCK==WSAGetLastError()) {
        handles[0] = evt;
        handles[1] = *recvCancelEvt;
        ret = WSAWaitForMultipleEvents(2, handles, FALSE, INFINITE, FALSE);
        if (WAIT_OBJECT_0 == ret) {
            bytesReceived = recv(handle->iSocket, (char*)buffer, bufferBytes, 0);
        }
    }
    WSACloseEvent(evt);
    return bytesReceived;
}

クライアント コードは、recv をキャンセルしたい場合にWSASetEvent呼び出します。recvCancelEvt

于 2013-01-18T10:20:26.480 に答える
1

Selectまたはblockingソケットに基づくソリューションは正しいアプローチですが、1つのコアを100%で実行している理由は、スリープの動作によるものです。-

WinAPI sleep()のドキュメントを見てください:

この関数により、スレッドはタイムスライスの残りの部分を放棄し、dwMillisecondsの値に基づいた間隔で実行できなくなります。システムクロックは一定の速度で「ティック」します。dwMillisecondsがシステムクロックの解像度よりも小さい場合、スレッドは指定された時間よりも短い時間スリープする可能性があります。

したがって、ポーリングする場合は、はるかに長いスリープ時間を使用するか(20Ms、通常はWindowsのティックレートよりも少し長い)、より正確なマルチメディアタイマーを使用する必要があります。

于 2013-01-18T10:41:07.313 に答える
0

ほとんどの場合、recvfrom を呼び出してもデータが返されないようです。1ミリ秒のスリープは大したことではありません。スリープ時間を増やすことを検討するか (安価ですが、最善の解決策ではありません)、より良い解決策として、イベント駆動型のアプローチを使用することを検討してください。または Windows API を使用select()して、ソケットが通知されるか、関心のあるその他のイベントが発生するまでブロックしてから、 を呼び出しますrecvfrom。そのためには、プログラムのメイン ループを再設計する必要がある場合があります。

于 2013-01-18T10:24:15.003 に答える
0

boost::asio::io_service の使用をお勧めします。最新の CPU を最大限に活用しながら、約 200MB/秒の UDP マルチキャスト トラフィックを受信します。これには、完全な信頼性プロトコルとアプリケーションへのデータ ディスパッチが含まれます。プロファイリングのボトルネックは処理であり、boost::asio の受信ではありません。コードはこちら

于 2013-01-18T11:19:08.483 に答える