2

ネットワーク経由でさまざまな種類のデータ (ビデオ ストリーム、オーディオ ストリーム、サービス通知など) を送信するクライアント サーバー Winsock アプリ (Visual C++) を開発しています。よりクリーンなアプローチは、個々のデータ型ごとに個別のスレッドで個別のポートを使用することであることを知っています (ここでは「ストリーム」と呼びます)。ただし、これには少なくとも 5 つの異なるポートを占有する必要があり、一部のネットワーク インフラストラクチャ (ファイアウォール ポート フォワーディングなど) で問題が発生する可能性があります。

だから私は1ポート接続(TCP)を実装しようとしています.1つのソケットだけが異なるストリームを送信するために使用されます. 個々のパケットには、それが属するストリーム、予想される合計メッセージ サイズなどを示す情報がヘッダーに含まれます。5 つの異なるストリームがあるとします。同じソケットのsend()を呼び出すために 5 つのスレッドを使用する予定です。これは安全ですか?異なるストリームからのパケットが混在して到着することはわかっていますが、送信された各パケットに必要なメタ情報を含めると、反対側で適切に再構築できますよね?

しかし、本当の問題は受信側です。同じソケットで複数のスレッドからsend()を呼び出すことはおそらく問題ありませんが (よくわかりませんので確認が必要です!)、複数のスレッドからrecv()を呼び出すことはあまり意味がありません。したがって、1 つのスレッドから 1つのブロッキングrecv()を使用する必要があります。しかし、パケット ヘッダー (特定のパケットが属しているストリームを特定する) に基づいて、異なるスレッドで処理をフォークする必要があります。ビデオ ストリームは 1 つのスレッド、サウンド ストリーム - 別のスレッドなどで処理する必要があります。パフォーマンスが最優先事項であるため、すべてのストリームを 1 つのスレッドで処理することは考えられません。

要約すると、次の 3 つの質問があります。

  • 複数のスレッドから同じソケットに対してsend()を呼び出しても問題ありませんか? (どの送信側スレッド (つまり、サブシステム) に属しているかに関する情報がパケット ヘッダーに含まれていると仮定します)。
  • 受信側に1 つのブロッキングソケットを持ち、単一のスレッドからループ内でrecv()を呼び出すと、異なる論理ストリームの受信パケットを異なるワーカー スレッドに「フォーク」する方法は?
  • 1 つのポートを介して複数のストリーム転送を実装するための追加の推奨事項は何ですか?

PS: 確かに、1 つのポートを複数のソケットで使用する方法はありませんね。

それは、Windows プラットフォーム、Winsock2、Visual C++ です (プラットフォーム固有の素晴らしいヒントを提供できれば)。

=更新=

  • 「ソケットをロックする」とは、send()関数へのアクセスをシリアル化するということですか? たとえば、クリティカル セクションで?

  • 受信側については...メッセージを組み立てると思います(ビデオフレームやサウンドサンプルなどの論理的な完全なデータ構造を「メッセージ」と呼びます)個々のストリームを個々のバッファーに)、次に、組み立てられたメッセージを (メッセージが完全に受信されたときに) フォーク スレッドに渡します。それが問題です - それらを渡す方法。私が考えた 1 つの方法は、イベント オブジェクトです。レシーバー スレッドからSetEvent()を呼び出して、 WaitForSingleObject()をトリガーします。(これはいくつかのループにあります)異なるスレッドで。これが許容できる解決策であるかどうかアドバイスできますか? もっと良いものを提案できますか?これを行う (同じアプリケーションの別のスレッドを「トリガー」する) ためのより高速なソリューションは、イベント オブジェクトよりもありませんか? そして、どのようにデータを渡すのですか?

4

2 に答える 2

3
  • 複数のスレッドから同じソケットに対して send() を呼び出しても問題ありませんか? (どの送信側スレッド (つまり、サブシステム) に属しているかに関する情報がパケット ヘッダーに含まれていると仮定します)。

もちろん、複数のスレッドから呼び出すこともできます。ただし、同期するにはソケットをロックする必要があることに注意してください。そうしないと、一貫性のない情報が書き込まれる可能性があります。

  • 受信側に 1 つのブロッキング ソケットを持ち、単一のスレッドからループ内で recv() を呼び出すと、異なる論理ストリームの受信パケットを異なるワーカー スレッドに「フォーク」する方法は?

ブースト asiosライブラリと同様に BeginRecv と EndRecv を作成するのはどうでしょうか(または Boost Asio に切り替えます。プラットフォームに依存しません!)。完全なメッセージを受信したら、それを送信できます。ネットワークから受信し続けるために、それを別の場所に置きたいと思いますか?CreateThreadを使用してパラメーターを介してデータを送信するだけlpParameterで、recv 以外の問題になります。次のパッケージをダウンロードする前に完全なパッケージをダウンロードする必要があるため、データをダウンロードする前にフォークすることにはあまり意味がありません。

  • 1 つのポートを介して複数のストリーム転送を実装するための追加の推奨事項は何ですか?

それについてはあまり知りませんが、recv() がどれほど不確実であるかを説明する Winsock に関する回答を以前に書きました。次のパッケージが作成される前に 1 つのパッケージが作成されるように同期することを忘れないでください。

「ソケットをロックする」とは、send() 関数へのアクセスをシリアル化するということですか? たとえば、クリティカル セクションで?

はい、そうです。たとえば、ロックにRAIIを使用することで、これをかなり行うことができます(その後、関数の戻り時に自動的に削除/ロック解除されます)。ただし、sendData最初にオブジェクトをロックしてからデータを送信する関数を使用してください。

それが問題です - それらを渡す方法。

まあ、新しいスレッドとして渡すだけです。

DWORD WINAPI myVideoProcessor(LPVOID theData){
    StructForKeepingVideoData* data = dynamic_cast<StructForKeepingVideoData*>(theData);
    // process the data that is passed in theData
    ...
}
...
void ReceiveData(){
    while (true){
        ...
        char buffer[SIZE];
        recv(mySocket, buffer, SIZE, 0);
        StructForKeepingVideoData* data = new StructForKeepingVideoData(buffer);

        HANDLE mId = CreateThread(NULL, 0, myVideoProcessor, data, 0, NULL);
        // now, the video processing will be done somewhere else. let's continue receiving data!
    }
}

私はここでちょっとぼんやりしています..しかし、データを転送するときにauto_ptrshared_ptrなどの構造を確認する必要があると思います-これはデータの破壊に役立ちます.

私が考えた 1 つの方法は、イベント オブジェクトです。レシーバー スレッドから SetEvent() を呼び出して、別のスレッドで WaitForSingleObject() (いくつかのループにある) をトリガーします。これが許容できる解決策であるかどうかアドバイスできますか?

イベントも同様に機能しますが、私が挑戦したことはありません。次に、処理するデータがあるときに開始するのではなく、スレッドを常に実行し続けるだけです。 データ転送の同期も維持する必要があることに注意してくださいsort if キューがある場合は、書き込みと読み取りが次々に行われるようにする必要があります。

もっと良いものを提案できますか?これを行う (同じアプリケーションの別のスレッドを「トリガー」する) ためのより高速なソリューションは、イベント オブジェクトよりもありませんか? そして、どのようにデータを渡すのですか?

より速いものは何もわかりません。ただし、データを渡すには、スレッドの作成時に行うか、同期を維持するある種のキューを使用します。

お役に立てれば。

于 2011-06-13T19:31:09.170 に答える
0

複数のスレッドから同じソケットに対して send() を呼び出しても問題ありませんか?

もちろん、ソケットをロックすれば。これを行う場合、すべての送信プロトコル ユニットを 1 つのスレッドにキューに入れ、それを使用して送信します。おそらく優先キューを使用して、必要なストリームへの迅速な配信を保証します。

異なる論理ストリームの受信パケットを異なるワーカースレッドに「フォーク」する方法は?

あなたのプロトコルはそれをしなければなりません。ビデオ/オーディオ/任意のプロトコル ユニットを着信バイトストリームから組み立て、PDU を適切なハンドラ スレッドのキューに入れます。

Windows - 高パフォーマンスが必要な場合はサーバーの IO 完了ポート。ビデオをストリーミングしようとしている場合は必要になります。

Rgds、マーティン

于 2011-06-13T13:46:53.903 に答える