0

サーバークラスとクライアントクラスがありますが、問題は次のとおりです。着信接続を受け入れるために無限ループを作成すると、接続が受け入れられるまでブロックを受け入れるため、接続を受け入れている間、クライアントから受信したすべてのデータを受信できません。私のコード:

    for (;;) 
    {
       boost::thread thread(boost::bind(&Irc::Server::startAccept, &s));
       thread.join();
       for (ClientsMap::const_iterator it = s.begin(); it != s.end(); ++it) 
       {
          std::string msg = getData(it->second->recv());
          std::clog << "Msg: " << msg << std::endl;
       }
    }
4

3 に答える 3

3

未処理のデータがある接続を見つける には、複数のスレッドまたはselect/の呼び出しが必要です。IBMには、ここに良い例があります。これは、Unix、Linux、BSDなどのあらゆるフレーバーで機能します(OSによっては異なるヘッダーファイルが必要になる場合があります)。poll

現在、スレッドを開始してすぐに待機しているため、順次実行され、スレッドの目的が完全に無効になります。

于 2010-11-13T19:29:39.660 に答える
0

ここを見てください:http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/examples.html

特にHTTP Server 3の例は、まさにあなたが探しているものです。あなたがしなければならないことは、必要に応じてそのコードを少し変更するだけです:)

于 2010-11-13T20:41:48.613 に答える
0

新しい接続のみを受け入れる 1 つのスレッドを作成することをお勧めします。そこにリスナーソケットがあります。次に、受け入れられるすべての接続に対して、新しい接続ソケットがあるため、別のスレッドを生成して、接続ソケットをパラメーターとして指定できます。そうすれば、接続を受け入れるスレッドはブロックされず、多くのクライアントに非常に高速に接続できます。処理スレッドはクライアントを処理し、終了します。

なぜそれらを待つ必要があるのか​​ さえわかりませんが、そうする場合は、使用するOSやライブラリに応じて、他の方法で処理することができます(メッセージ、シグナルなどを使用できます)。

接続されたクライアントごとに新しいスレッドを生成したくない場合は、Ben Voigt が提案したように、select を使用できます。シングルスレッドにしたい場合、これは別の良いアプローチです。基本的に、すべてのソケットはソケット記述子の配列にあり、選択を使用すると、何が起こったのか (誰かが接続されている、ソケットが読み取り/書き込みの準備ができている、ソケットが切断されているなど) を知り、それに応じて動作します。

ここに 1 つの例を示します。部分的なものですが、機能します。acceptConnections() で接続を受け入れるだけで、クライアントごとに個別のスレッドが生成されます。そこでお客様とコミュニケーションを取ります。それは私が横たわっているWindowsコードからのものですが、どのプラットフォームでも再実装するのは非常に簡単です.

typedef struct SOCKET_DATA_ {
  SOCKET sd;
  /* other parameters that you may want to pass to the clientProc */
} SOCKET_DATA;

/* In this function you communicate with the clients */
DWORD WINAPI clientProc(void * param)
{
    SOCKET_DATA * pSocketData = (SOCKET_DATA *)param;

    /* Communicate with the new client, and at the end deallocate the memory for
       SOCKET_DATA and return.
    */

    delete pSocketData;
    return 0;
}

int acceptConnections(const char * pcAddress, int nPort)
{
    sockaddr_in sinRemote;
    int nAddrSize;
    SOCKET sd_client;
    SOCKET sd_listener;
    sockaddr_in sinInterface;
    SOCKET_DATA * pSocketData;
    HANDLE hThread;

    sd_listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (INVALID_SOCKET == sd_listener) {
        fprintf(stderr, "Could not get a listener socket!\n");
        return 1;
    }

    sinInterface.sin_family = AF_INET;
    sinInterface.sin_port = nPort;
    sinInterface.sin_addr.S_un.S_addr = INADDR_ANY;

    if (SOCKET_ERROR != bind(sd_listener, (sockaddr*)&sinInterface, sizeof(sockaddr_in))) {
        listen(sd_listener, SOMAXCONN);
    } else {
        fprintf(stderr, "Could not bind the listening socket!\n");
        return 1;
    }

    while (1)
    {
        nAddrSize = sizeof(sinRemote);
        sd_client = accept(sd_listener, (sockaddr*)&sinRemote, &nAddrSize);

        if (INVALID_SOCKET == sd_client) {
            fprintf(stdout, "Accept failed!\n");
            closesocket(sd_listener);
            return 1;
        }

        fprintf(stdout, "Accepted connection from %s:%u.\n", inet_ntoa(sinRemote.sin_addr), ntohs(sinRemote.sin_port));
        pSocketData = (SOCKET_DATA *)malloc(sizeof(SOCKET_DATA));

        if (!pSocketData) {
            fprintf(stderr, "Could not allocate memory for SOCKET_DATA!\n");
            return 1;
        }

        pSocketData->sd = sd_client;
        hThread = CreateThread(0, 0, clientProc, pSocketData, 0, &nThreadID);

        if (hThread == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "An error occured while trying to create a thread!\n");
            delete pSocketData;
            return 1;
        }
    }

    closesocket(sd_listener);
    return 0;
}
于 2010-11-13T19:49:40.247 に答える