ネットワークストリームとは、アプリケーションから別のアプリケーションにTCPと同等のスループットとレイテンシ特性でデータを転送するための、構成しやすく、緊密に統合されたダイナミックな通信方法です。 ネットワークストリームは、TCPとは違い、データを最初に中間データタイプに平坦化/非平坦化する必要なく、任意のデータタイプの送信を直接サポートします。 ネットワークストリームは、データを下位互換形式で送信するので、異なるバージョンのLabVIEWランタイムエンジンを使用しているアプリケーション間でも安全かつ正常に通信が可能です。 また、ネットワーク障害やその他のシステム障害により接続を失っても、自動的にネットワーク接続を回復できる高度な接続管理機能を備えています。 ストリームは、バッファされた損失のない通信方法であるため、ネットワーク接続が途中で途切れても、ストリームに書き込まれたデータは損失しません。
ネットワークストリームは損失のない、高スループットのデータ通信として設計および最適化されています。 ネットワークストリームは、アプリケーション間でデータを通信するための、単一方向、ポイントツーポイントのバッファ型通信モデルです。 つまり、一方のエンドポイントがデータの書き込み、もう一方がデータの読み取りを行います。 各コンピュータで相手側のコンピュータのライタとペアにされたリーダと相手側のリーダとライタとペアにされたライタの2つのストリームを使用することにより、双方向通信が実現できます。
ストリームのスループット特性が未処理TCPと同等なので、TCPを使用する際の複雑さに時間をかけずに高スループットのアプリケーションを作成したい場合に最適です。 ストリームは、コマンドの送受信など、ロスレスの低スループットの通信にも使えます。 しかし、低スループットの通信にストリームを使用する場合は、最も遅いレイテンシにしたい場合は、ストリームにデータを送信するタイミングをより明示的に管理することが必要な場合があります。
ネットワークストリームを使用してデータを作成およびストリームするには、以下の手順に従います。
1. エンドポイントを作成し、ストリーム接続を確立する
2. データを読み取る/書き込む
3. エンドポイントを破棄する
次の図は、これらの手順を実装したものです。
以降のセクションでは、前のセクションで示した一般的な手順について詳しく説明するとともに、アプリケーションを設計および実装するときに考慮すべきパフォーマンス項目を挙げます。
LabVIEWは、各ストリームエンドポイントをURLによって識別します。 2つのエンドポイントを接続して、有効なネットワークストリームを作成するには、「ネットワークストリーム読み取りエンドポイントを作成」関数または「ネットワークストリーム書き込みエンドポイントを作成」関数を使用してリモートエンドポイントのURLを指定する必要があります。 予約されている文字のエスケープコードなど、エンドポイントURLの詳細については、『LabVIEWヘルプ』の「ネットワークストリームエンドポイントURL」トピックを参照してください。 URLの簡単な説明は、次のとおりです。
ストリームエンドポイントの完全なURLは、次のとおりです。
ni.dex://host_name:context_name/endpoint_name
このURLの各コンポーネントの説明は、以下のとおりです。
エンドポイントの作成関数で指定する必要があるURLは、リモートマシンのネットワーク場所と、エンドポイントを作成したときに付けた名前に依存します。
ネットワークストリームは、書き込みエンドポイントと読み取りエンドポイントの接続です。 エンドポイントは、「ネットワークストリーム書き込みエンドポイントを作成」関数または「ネットワークストリーム読み取りエンドポイントを作成」関数を使用して作成します。
エンドポイントを作成すると、2つのエンドポイントを接続するときに重要な複数のプロパティをエンドポイントに設定します。
エンドポイントの方向は、呼び出された作成関数により暗示的に決定され、読み取り専用と書き込み専用のどちらにすることもできます。 エンドポイント名は、作成関数の書き込み名または読み取り名入力により指定します。 この名前は、エンドポイントリソースを識別するURLを生成するために使用されるので、固有である必要があります。 指定した名前のエンドポイントがすでに存在する場合は、作成関数はエラーを返します。 名前は単純な文字列にすることも、完全準拠のURLにすることもできます。 有効なエンドポイントURLになる条件について詳しくは、URLセクションを参照してください。 リモートマシンに存在する既存のエンドポイントに接続することはできますが、リモートエンドポイントを作成することはできません。 エンドポイントを作成できるのは、VIを実行するローカルマシンに対してのみです。
ネットワークストリームは、TCPとは異なり、データを文字列に平坦化したり、文字列から非平坦化したりすることなく、LabVIEWデータの送信を直接サポートします。 ほとんどのLabVIEWデータタイプは、ネットワークストリームで直接サポートされています。 しかし、そのタイプの一部にオブジェクトリファレンスまたはLabVIEWクラスを含むデータタイプは例外なので、注意する必要があります。 クラスは、まず最初に、適切なクラスデータを直列化および非直列化する変換メソッドをクラス上に作成することで、間接的に転送できます。 リファレンスはローカルマシン上のオブジェクトを参照するトークンなので、リファレンストークンをリモートコンピュータで使用するためにネットワーク経由で送信しようとすることは、通常、意味がありません。 唯一の例外は、NI Vision Developmentモジュールがインストールされているときに使用できるVision Imageデータタイプです。 この場合、画像データの転送は、Vision Imageデータへのリファレンスを使用することてで、ストリームにより直接サポートされます。 ストリームで直接サポートされないデータに関しては、サポートされているタイプの1つにデータを変換/逆変換する変換コードが必要です。 また、データタイプによっては、ストリーム経由での転送効率に差があります。 データタイプの選択がストリームのパフォーマンスに与える影響については、「パフォーマンスの考慮点」を参照してください。
作成関数は、エンドポイントリソースを作成するほか、書き込みエンドポイントと読み取りエンドポイントを結ぎ合わせて完全に機能するストリームを形成します。 最初に作成されたエンドポイントは、もう1つのエンドポイントが作成され、接続の準備ができるまで待機します。相手のエンドポイントで接続の準備ができたときに、関数は終了します。 これで、ストリームはデータ転送ができるようになります。 このように使用することで、作成関数は、ストリームの両側の準備ができるまで、または作成関数がタイムアウトするまで、どちらの関数も先に進まない、ネットワークランデブーにとして機能します。
2つのエンドポイントの間でストリームを確立するには、3つの条件が満たされる必要があります。
1. 両方のエンドポイントが存在する。 さらに、両方の作成関数でリンクするリモートエンドポイントURLが指定されている場合、両方のURLが、リンクされるエンドポイントと一致している必要があります。
2. 2つのエンドポイントのデータタイプが一致している。
3. 1つのエンドポイントが書き込み専用エンドポイントであり、もう1つのエンドポイントが読み取り専用エンドポイントである。
作成関数の実行時に条件1が満たされていない場合、作成関数は、タイムアウトになるまで待機し、その時点でまだ条件が満たされていない場合は、エラーが返されます。 両方のエンドポイントで、リンク先のエンドポイントをしてあり、1つのURLしか一致していない場合、1つの作成関数はエラーを返し、もう1つの作成関数は、タイムアウトになるまで待機します。
上の例の場合を考えると、“reader1”エンドポイントが“writer1”ではなく、“some other writer”という名前のエンドポイントを期待しているため、左側の作成呼び出しはエラーを返します。 しかし、右側の作成呼び出しは“some other writer”という名前のエンドポイントがタイムアウトするまで待機してから、タイムアウトエラーを返します。 条件2または3が満たされていない場合、その2つのエンドポイントがストリームを形成できない構成であることが判明次第、作成関数はエラーを返します。
エンドポイントを作成するときは、少なくとも1つのエンドポイント作成関数の読み取りURLまたは 書き込みURL入力で、相手のエンドポイントのURLを指定する必要があることに注意してください。 指定しなかった場合、両方の作成関数は、タイムアウトエラーを返すことになります。 読み取りエンドポイントと書き込みエンドポイントの両方の作成関数の中で、相手のURLを指定することもできますが、必要なのは1つだけです。 移植性とメンテナンス性に優れたコードを開発するために、読み取りエンドポイントと書き込みエンドポイントのいずれか1つで相手エンドポイントのURLを指定し、両方では指定しないことを推奨します。
ストリームエンドポイントは、エンドポイントから別のエンドポイントにデータを転送するためにFIFOバッファを使用します。 バッファサイズは作成時に指定され、作成呼び出しのときにバッファが割り当てられます。 バッファのサイズは要素の単位で指定します。バッファ内の要素は、そのストリームのデータタイプで指定されるタイプの単一値を表します。 このため、エンドポイントが消費するメモリ量の合計は、バッファサイズとストリームのデータタイプによって異なります。
ブールや数値などのスカラデータタイプのサイズは一定で前もってわかっているので、スカラデータタイプの場合にエンドポイントバッファが消費するメモリ量は、簡単に計算できます。 たとえば、倍精度浮動小数点数は常に8バイトのメモリを消費するので、倍精度浮動小数点数1,000要素のバッファは8,000バイトのメモリを消費します。
これに対して、クラスタ、文字列、配列などの非スカラデータタイプを扱う場合のメモリ消費量は、単純ではありません。 これらのデータタイプのサイズは実行時で異なるので、必要なメモリ合計はエンドポイントの作成時には不明です。 この場合、エンドポイントの作成時に割り当てられるバッファは、各要素がバッファ内のその要素に書き込まれる値へのポインタまたはハンドルを保持できるだけのの大きさになります。 そして、実行時、要素がバッファに書き込まれるときに各要素のデータ値を格納するのに必要なメモリが、動的に割り当てられます。 次の図は、バッファサイズが3で、要素データタイプが1D配列のストリームエンドポイントの概念を表しています。
ステップAは、作成直後のエンドポイントバッファを表しています。 この時点では、エンドポイントにデータ値は書き込まれておらず、各要素には、その要素のデータ値を格納するメモリブロックへのポインタを格納できるだけのメモリが割り当てられています。
ステップBは、3つのデータ値が書き込まれた後のエンドポイントバッファを表しています。 要素1には、長さ2の配列が含まれています。 要素2には、長さ4の配列が含まれています。 最後の要素3には、長さ3の配列が含まれています。 これはバッファに対する最初の書き込みなので、書き込みは、各データ値を格納するために十分なメモリブロックを動的に割り当てます。
ステップCは、3つのデータ値が読み取られた後のエンドポイントバッファを表しています。 バッファからすべての値が読み取られても、各データ値に割り当てられたメモリは解放されないことに注意してください。 メモリ空間は、バッファのその位置に次のデータ値を格納するために再利用できるようにそのまま残ります。
ステップDは、さらに長さ3のデータ値2つが書き込まれた後のエンドポイントバッファを表しています。 この場合、要素1が保持していたメモリブロックのサイズが新しいデータ値を格納するのに十分でなかったため、これより大きなメモリブロックが割り当てられました。 これに対し、要素2が保持していたメモリブロックのサイズは新しいデータ値を格納するのに十分だったため、再利用されました。 要素2が保持していたメモリブロックのサイズは必要なサイズより大きくても、それを解放して、最低限必要なサイズのメモリブロックを新しく割り当てるオーバーヘッドを発生させるのではなく、そのまま再利用されたことに注意してください。 一度要素に割り当てられたメモリブロックは、エンドポイントが破棄されるまで、解放されたり、サイズを減少されることはありません。
このプロセスで表されているとおり、非スカラデータタイプのエンドポイントバッファサイズを選択するときには注意が必要です。 データ要素とバッファサイズが大きい場合は、エンドポイントが破棄されるまで、大量のメモリが消費される場合があります。 これは、スカラデータタイプの場合も同様です。 しかし、スカラデータタイプに必要なメモリは、すべてエンドポイントの作成時に一度に割り当てられるため、メモリの問題をデバッグするのは、通常は簡単です。 これに比べ、非スカラタイプに必要なメモリのほとんどは、最初にバッファに書き込まれるときに割り当てられます。 これは、エンドポイントバッファへの書き込み時にメモリ不足になるまでの間、アプリケーションは正常に稼動する場合があるため、メモリリークのように見えることがよくあります。
ストリームへのすべての読み取り/書き込み呼び出しが、トランザクション的な性質の呼び出しをすべてブロックしています。 要求された数の要素を正しく読み取る/書き込むか、タイムアウトします。 タイムアウトした場合は、部分的なデータの読み取り/書き込みはされず、データの上書きや再生成はされません。 読み取り呼び出しがタイムアウトした場合、データ出力端子は、構成されているデータタイプのデフォルト値を返します。 このため、1回の呼び出しで読み取り/書き込みできる要素の最大数は、エンドポイントのバッファサイズにより制限されます。 エンドポイントのバッファサイズを超えた数の要素を読み取り/書き込みしようとすると、すぐにエラーになります。
ネットワークストリームは、データの読み取り/書き込み時に単一要素インタフェースと複数要素インタフェースの両方を提供しています。 単一要素読み取り/書き込みは、一度にバッファに追加/削除できる要素は1つであるのに対して、複数要素読み取り/書き込みは、データをバッチで追加/削除することができます。 タイプの異なる読み取り/書き込みを使用する場合、ブロックダイアグラムに表示されるデータの外観は異なります。 下の例では、ストリームのデータタイプは倍精度浮動小数点数です。 単一要素書き込みを使用したストリーム書き込みは、ブロックダイアグラム上で倍精度のデータタイプで表されます。 これに対して、複数要素書き込みのデータ入力端子のデータタイプは、倍精度配列のデータタイプで表されます。
下の図は、この違いを表しています。 矢印の左側の要素は、書き込みが発生する前の書き込みエンドポイントバッファを表しており、矢印の右側の要素は、書き込みが発生した後のエンドポイントバッファを表しています。 最初、書き込みエンドポイントバッファに2つの要素があった場合、最初に単一要素書き込みを実行するとバッファに1つの要素が追加され、バッファ内の合計要素数は3つになります。 これに対して、ストリームへの複数要素書き込み関数を使用して3つの要素を書き込んだ場合、バッファ内の要素の合計数は、5になります。
配列のような、非スカラデータタイプの場合、上の図は同じが、個々の要素の中身は配列タイプになり、長さは可変です。 この場合、単一要素書き込みのデータタイプは1D配列で、複数要素書き込みのデータタイプは2D配列です。 下の図は、これを表しており、上向き矢印とその上のブロックは配列とそのサイズを表しています。
同様に、複数要素読み取りは、指定された数の要素を読み取りエンドポイントバッファから削除します。 しかし、LabVIEW内の多次元配列構造の制限から、配列要素の次元の長さは、すべて同じである必要があります。 複数要素読み取りの場合、これは、配列要素の次元の長さが異なる複数要素を読み取ろうとすると、読み取り関数は、エラーを返すことを意味します。 図4を例にして考えると、これは、 最初の要素、2番目の要素、3~5番目の要素をそれぞれ単一読み取り呼び出しで読み取れることを意味します。 しかし、1~3番目の要素の任意の組み合わせ読み取ろうとする読み取り呼び出しは、配列要素の次元の長さが異なるので、エラーを返します。 単一/複数要素読み取り/書き込みは、同じバッファから要素を削除/追加するので、マルチレートアプリケーションでは、必要に応じて、単一/複数要素読み取り/書き込みを組み合わせて使用できます。
複数要素読み取り関数の要素数入力に-1を指定すると、利用できるすべてのサンプルが読み取られます。
これは、「読み取り可能な要素」プロパティを読み取って、その戻り値を読み取り関数の要素数入力として使用することと同じであり、同じことを簡単に実行する方法です。 このように使用する場合、読み取り関数のタイムアウト(ms)入力は無効にされたのと同じです。 読み取る要素がない場合、読み取り関数は、タイムアウトやエラー状態を示すことなく空のデータ配列をすぐに返します。
エンドポイント間でデータをストリームする必要がなくなった場合、「ストリームエンドポイントを破棄」関数」を呼び出すことにより、どちらのエンドポイントからの通信も終了させることができます。
しかし、書き込みエンドポイントを破棄する前に、ストリームに書き込まれたすべてのデータを読み取りが確実に受け取るようにするには、まず、「ストリームを排出」関数を呼び出し、適切な待機状態が満たされるのを待ってから、書き込みエンドポイントを破棄してください。 破棄関数を呼び出せるのは、書き込みエンドポイントのみです。
破棄関数は、まず、書き込みエンドポイントバッファに残っているデータをネットワークに即時転送します。 次に、指定した条件が満たされるか、タイムアウトになるまで待機します。 「ストリームを排出」関数には、次の2つの条件があります。
「すべての要素をストリームから読み取る」を指定した場合、排出関数は、全データが読み取りエンドポイントに転送され、読み取りエンドポイントから全データが読み取られるまで待機してから戻ります。 「すべての要素は読み取り可能」オプションは、読み取りエンドポイントに全データが転送されるまで待機しますが、読み取りエンドポイントから全データが読み取られるまで待機しません。 下のダイアグラムで見ると、「すべての要素をストリームから読み取る」オプションは、ステップCの後で排出関数から戻り、「すべての要素は読み取り可能」オプションは、ステップDの後で排出関数から戻ります。
書き込みエンドポイントを破棄する前に、排出関数を呼び出さない場合、送信中のデータや書き込みエンドポイントバッファに残っているデータが失われる可能性があることを意味します。 このため、アプリケーションの通信を即時に終了する必要があり、これにより失われる可能性のあるデータが不要な場合以外は、ストリームを破棄する前に、排出関数を呼び出すことを推奨します。
一度、読み取りエンドポイントに対して破棄が呼び出されると、書き込みエンドポイントからの以降の書き込み呼び出しはエラーになります。 書き込みエンドポイントが破棄されると、読み取りエンドポイントからの以降の読み取り呼び出しは、読み取りエンドポイントバッファが空になるまで成功し、空になった時点で読み取り呼び出しはエラーを返します。 バッファに残っているよりも多くの要素に対して複数要素読み取りが受信された場合、読み取り要求はバッファに残っている要素を返します。以降の読み取り要求はエラーになります。 これは、複数要素読み取りがタイムアウトまたはエラー状態を示さずに、要求された未満のポイントを返す唯一の場合です。
ネットワークストリームには、続行中のデータストリームに関する情報を取得するために、アプリケーションが監視できる複数のプロパティがあります。 この中のいくつかについて、以下で詳しく説明します。 他のプロパティに関しては、『LabVIEWヘルプ』の「ネットワークストリームエンドポイント」ページを参照してください。
「読み取り可能な要素」は、読み取りエンドポイントが、エンドポイントバッファに存在する未読の要素数を返すために使用されます。 これは、読み取りエンドポイントバッファ使用率を調べるのに便利で、読み取りエンドポイントから読み取られたときに有効な結果だけを返します。 同様に、「読み取り可能な要素」プロパティは、エンドポイントバッファに存在し、書き込まれていない要素数を返します。 アプリケーションのプロトタイプ作成時には、読み取りと書き込みの処理が遅れていないかを確認するために、バッファ使用率を監視するのが便利な場合がよくあります。 この情報は、アプリケーション内のボトルネックを探し、アプリケーション全体の要件を満たしつつ、消費されるメモリリソースを最小化するために、エンドポイントバッファのサイズを調節するために使用できます。
接続プロパティは、読み取りエンドポイントと書き込みエンドポイントの間のネットワーク接続の状態を示します。 接続プロパティがFALSEの場合、「ストリームエンドポイントを破棄」関数を使用して他方のエンドポイントが破棄されたか、2つのエンドポイント間のネットワーク接続が中断されていることを示します。 ネットワークの中断の場合、エンドポイントは、中断が解決するか、エンドポイントが破棄されるまで、バックグラウンドで再接続が試行されます。
「切断の数」は、 ネットワークに問題があるか、リモートエンドポイントが破棄されたことで、読み取りエンドポイントと書き込みエンドポイント間のネットワーク接続が中断された回数を返します。 このプロパティは、接続プロパティと組み合わせて使用することで読み取りとエンドポイントと書き込みエンドポイントを接続しているネットワークの安定性とヘルスを確認できます。
前述のとおり、ネットワークストリームは、書き込まれた全データがストリームから読み取られるか、そのストリームが破棄されるまで、それを保持するポイントツーポイントの通信チャンネルを提供します。 このロスレスデータ転送は、エンドポイントバッファにFIFOバッファポリシーを使用すること、および確認とフロー制御プロトコルメッセージにより実現されます。 FIFOバッファポリシーは、書き込みエンドポイントが含まれているアプリケーションがネットワークの転送速度よりも速くデータを書き込もうとしている場合にデータを上書きされることを防ぎます。 確認メッセージは、ネットワーク切断によるデータ損失を防ぎ、フロー制御メッセージは、読み取りエンドポイントが含まれているアプリケーションが消費できるより速い速度で、書き込みエンドポイントが含まれているアプリケーションがデータを生成しようとしている場合にデータが上書きされることを防ぎます。 次のシーケンスダイアグラムは、ロスレスデータ通信を実現するために、これらのメッセージが使用される方法を詳しく表しています。
1. タイムスロット1は、両方のバッファが空のときに3つの要素を書き込む要求を表しています。
2. 書き込みエンドポイントは、データを上書きせずに3つの要素を受け入れることができるので、書き込み要求は完了し、書き込みエンドポイントには3つの要素が入ります。
3. 書き込みエンドポイントは、3つの要素を読み取りエンドポイントに送信します。 ここでは、読み取りエンドポイントからの確認待ちの状態で、要素が占められていることを示すために、書き込みエンドポイント内の3つの要素を赤色で示してあります。 確認を受け取るまで、書き込みはこれらの3つの要素を保持しなければならず、送信できるのは、あと2つの要素だけです。
4. 読み取りエンドポイントは、書き込みから3つの要素を受信します。 2つの要素の書き込み要求が書き込みエンドポイントに対して出されます。
5. 読み取りエンドポイントは、3つの要素の確認を送信します。 書き込みエンドポイントは、データを上書きせずに2つの要素を受信できるので、タイムスロット4からの以前の書き込み要求は完了し、書き込みエンドポイントに含まれる要素は5つになります。
6. 書き込みエンドポイントは、3つの要素の確認を受信します。 3つの要素はエンドポイントバッファから削除され、書き込みエンドポイントに含まれる要素は2つになります。
7. 書き込みエンドポイントは、2つの要素を読み取りエンドポイントに送信します。 しかし、その途中で、ネットワークが中断され、データは読み取りエンドポイントに受信されませんでした。
8. 4つの要素の書き込み要求が受信されました。 書き込みエンドポイントがデータを上書きせずに受信できる要素は3つだけなので、書き込み呼び出しはブロックします。
9. ストリームはネットワーク接続を修復して、2つの要素が送信されたが、受信されていないことを検知します。 これらの要素は、再接続プロセスの一部として再送されます。
10. 再送された2つの要素が読み取りエンドポイントに受信されます。 読み取りには、2つの要素が入り、満杯になりました。 書き込みは、読み取りエンドポイントからデータが読み取られるまで、要素は送信できません。
11. 読み取りエンドポイントは、2つの要素の確認を送信します。 それと同時に、2つの要素の読み取り要求を受信します。
12. 書き込みエンドポイントは、2つの要素の確認を受信すると、エンドポイントバッファからそれらを削除します。 これで書き込みは空になりました。 読み取りには5つの要素があるので、以前の2つの要素の読み取り要求を完了して、2つの要素のフロー制御メッセージを書き込みエンドポイントに送信して、オーバーフローにならずにもう2つの要素が受信できることを知らせます。 これで、読み取りエンドポイントに含まれる要素は3つになりました。
13. 書き込みには5要素分の空きがあるので、ブロックされていたタイムスロット8からの書き込み要求を完了します。 これで、読み取りに含まれる要素は4つになりました。 さらに、読み取りエンドポイントから2つの要素のフロー制御メッセージを受信します。 次のフロー制御メッセージを受信するまで、読み取りエンドポイントに送信できる要素は、あと2つまでです。
前のセクションでは、ネットワークストリームが、ネットワーク障害が発生したときでもロスレスデータ転送を維持する仕組みを説明しました。 このセクションでは、この再接続プロセスの仕組みについて説明します。
ネットワークストリームでは、1つのエンドポイントがアクティブエンドポイントと指定され、もう1つのエンドポイントがパッシブエンドポイントと指定されます。 アクティブエンドポイントは、最初にネットワーク接続を開始する側のエンドポイントで、ネットワークの状況が切断になったことを検知すると再接続を試行する責任があります。 他方のパッシブエンドポイントは、接続要求を待つ側です。 クライアント/サーバの用語で言えば、アクティブエンドポイントはクライアントであり、パッシブエンドポイントはサーバになります。 どのエンドポイントがアクティブエンドポイントになるかは、エンドポイントを作成する関数で指定します。 接続先のリモートエンドポイントのURLを指定するエンドポイントはアクティブエンドポイントに指定され、リモートエンドポイントのURLを指定しないエンドポイントはパッシブエンドポイントに指定されます。
上の図では、左側の書き込みエンドポイントが接続先の読み取りエンドポイントのURLを指定しているので、アクティブエンドポイントになります。 また、左側の書き込みエンドポイントが接続先の読み取りエンドポイントのURLを指定していないので、パッシブエンドポイントになります。 もし、両方のエンドポイントで接続先のリモートエンドポイントを指定した場合、どちからがアクティブエンドポイントになるかは不確定で、プロトコルメッセージがネットワークで送受信される順序に依存します。
接続が切断された場合、アクティブエンドポイントは、バックグラウンドでパッシブエンドポイントとの接続を試行し続けます。 このバックグラウンドプロセスは、接続が確立されるか、エンドポイントが破棄されるまで続行されます。 接続が切断されている間、書き込みエンドポイントへの書き込みは、書き込みエンドポイントが満杯になるまでは成功します。読み取りエンドポイントへの読み取りは、読み取りエンドポイントが空になるまでは成功します。 書き込みエンドポイントが満杯になるか、読み取りエンドポイントが空になると、読み取りおよび書き込み呼び出しはブロックし、適宜、タイムアウト表示を返します。 しかし、読み取り/書き込み呼び出しはエラーを返しません。
エンドポイントバッファは不安定なネットワークによるジッタからはある程度保護されますが、ネットワークが長期間、切断された状態が続くと、やがて満杯になるか、空になります。 アプリケーションがネットワークの長期間の切断を許容できるようにするには、予期される最長のダウンタイムを吸収できるバッファサイズにするか、切断状態でのタイムアウト状態を処理するためのロジックを実装する必要があります。 また、ストリームはネットワーク接続が接続されたことは検知できますが、それがネットワークの問題なのか、リモートエンドポイントが含まれているアプリケーションがクラッシュした/応答しないことによるのかは識別できません。 クラッシュした/応答しない場合、クラッシュしたエンドポイントがアクティブエンドポイントの場合、続行中のパッシブエンドポイントは再接続を受信するまで永久に待機します。 リモートアプリケーションは応答していないので、このメッセージは到達せず、ローカルアプリケーションのストリーム接続は、それ以上、進みません。 アプリケーションがリモートアプリケーションのクラッシュ/応答停止を許容する必要がある場合は、一定間隔で接続プロパティを監視し、妥当な時間内に通信を再確立できない場合に適切な処理をする、独自のウォッチドッグタイマを実装することを推奨します。
ネットワークストリームのパフォーマンスを調整する際の2つの一般的な測定基準は、スループットとレイテンシです。 スループットとレイテンシの測定値は、通信関連システムの仕様、通信ネットワークインタフェース、ネットワーク全体の混雑度と信頼性など、複数の要因に依存します。 これらの要因は重要ですが、このドキュメントの目的を超えるため、説明は割愛します。 このドキュメントでは、アプリケーション内でプログラム的に構成できる、ネットワークストリーム特有のプロパティを取り上げて説明します。
ネットワークストリームのスループットを制限する一般的な要因を、以下に示します。
1. 書き込みアプリケーション – 書き込みエンドポイントが含まれているユーザーアプリケーション。 これには、通常、書き込み関数を呼び出すループが含まれています。
2. 書き込み関数 – 書き込み関数は、書き込みアプリケーションからデータを受信して、書き込みエンドポイントに転送するコストを表します。
3. ネットワークストリームエンジン – これは、バックグラウンドで、書き込みエンドポイントから読み取りエンドポイントに非同期にデータを移動し、読み取りエンドポイントから書き込みエンドポイントに確認メッセージとフロー制御メッセージを送信するプロセスです。
4. 読み取り関数 – 読み取り関数は、読み取りエンドポイントからデータを削除して、読み取りアプリケーションに転送するコストを表します。
5. 読み取りアプリケーション – 読み取りエンドポイントが含まれているユーザーアプリケーション。 これには、通常、読み取り関数を呼び出すループが含まれています。
書き込みアプリケーション、ネットワークストリームエンジン、読み取りアプリケーションは、すべて互いに並列して実行されるプロセスであり、ストリーム全体でのスループットは、この中で最も遅いプロセスによって決まります。 ここでは、書き込み関数の実行時間は書き込みアプリケーションの一部に含まれており、読み取り関数の実行時間は読み取りアプリケーションの一部に含まれています。 これらのプロセスには、複数のストリームプロパティが影響を与えます。次に、それらについて説明します。
ストリームエンドポイントのデフォルトバッファサイズは、4096要素です。 非スカラ要素のサイズは非常に大きくなることがあるため、この値は、非スカラデータタイプ用に大量のメモリを消費せずに、スカラデータタイプで良好なスループットを実現できる点で適切な値といえます。 しかし、スカラ/非スカラのデータタイプのスループットとメモリ使用率の適切な妥協点ではあるものの、一般的、どちらの場合にとっても最適な設定にはなりません。 スカラデータタイプの場合、ネットワークインタフェースで最大のスループットを実現するには、エンドポイントバッファサイズは100,000から1,000,000程度にする必要があります。 非スカラデータタイプの場合、これよりも大幅に小さなバッファで最大のスループットが実現できます。
残念なことに、最適なバッファサイズを決める単純な公式はありません。 開発時に、さまざまなバッファサイズで試してみることで、アプリケーションのニーズに応えるために最適な設定を決める必要があります。 プロトタイプ作成の一環として、「読み取り可能な要素」プロパティと「書き込み可能な要素」プロパティを使用することで、各エンドポイントバッファがどれだけ効果的に使用されているか、現在のバッファサイズがアプリケーションのボトルネックになっているかどうかを判断できます。
たとえば、目的のスループットが得られずに、書き込みエンドポイントが常に満杯かほぼ満杯の場合、ネットワークストリームエンジンが書き込みアプリケーションに追いついていないことを表しています。 この状態は、ネットワークが飽和して、スループットの上限に達しているか、書き込みエンドポイントバッファが小さすぎることを表しています。 後者の場合、ネットワークストリームエンジンが書き込みエンドポイントから要素を送信し、読み取りエンドポイントから書き込みエンドポイントに確認メッセージとフロー制御メッセージを送信する際のネットワークでの遅れが原因で書き込みアプリケーションのループレートが制限されています。 この場合、書き込みエンドポイントバッファサイズを増やすことでスループットを改善できます。
同様に、目的のスループットが得られずに、読み取りエンドポイントバッファが常に空かほぼ空の場合、ネットワークストリームエンジンが読み取りアプリケーションに追いついていないことを表しています。 この状態も、ネットワークが飽和して、スループットの上限に達しているか、読み取りエンドポイントバッファが小さすぎることを表しています。 ネットワークが飽和に達していないと仮定すると、読み取りエンドポイントのバッファサイズを増やすと、多くの場合、スループットが改善します。
最大スループットのほかにも、ネットワークが一時的に使用できなくなった場合でもストリームが最低平均レートを維持する必要があるかどうかを検討する必要があります。 たとえば、計測デバイスから電圧データを100 kB/sで連続的に集録する場合、最適条件では、データ転送を維持するのに10 kBのエンドポイントバッファがあれば十分な場合があります。 しかし、計測デバイスからのデータを損失なく、10秒間の停電に耐えられるようにするには、最低でも1 MBの書き込みエンドポイントバッファが必要です。
データを読み取る/書き込む場合、読み取り関数または書き込み関数を呼び出すたびに、その関数により転送されるデータ量とは関係なく、その関数を呼び出すために必要な固定コストが発生ことに注意してください。 比較的、少量のデータセットで頻繁に読み書きを実行すると、関数の固定オーバーヘッドの実行により消費される合計時間が、ますます長くなります。 このオーバーヘッドがあまりに大きくなると、書き込みアプリケーションまたは読み取りアプリケーションを実行するプロセッサの使用率が100%になり、飽和する場合があります。 この場合、プロセッサは、ネットワークストリームエンジンに遅れない速度でアプリケーションループを実行できなくなり、アプリケーションがボトルネックになります。
この問題を診断するには、アプリケーションを実行しているプロセッサの使用率とエンドポイントバッファの使用率を確認します。 プロセッサの使用率が100%であり、書き込みエンドポイントバッファが空または、ほとんど常に空であれば、書き込みアプリケーションがネットワークストリームエンジンに追いついていないことを表しています。 同様に、プロセッサの使用率が100%であり、読み取りエンドポイントバッファが満杯または、ほとんど常に満杯であれば、読み取りアプリケーションがネットワークストリームエンジンに追いついていないことを表しています。 いずれの場合も、1回の呼び出しで読み取る/書き込む要素数を増やすことで、全体的なスループットが向上する場合があります。 可変サイズデータタイプの場合は、別の方法として、ストリームに書き込む各要素のサイズを大きくする方法もあります。 たとえば、要素タイプが1D配列の場合、要素数が10の配列を1,000個書き込むのではなく、要素数が10,000の配列を1つ書き込んでみてください。
小さすぎるデータを一度に読み書きするとスループットに悪影響であるのと同様、大きすぎるデータを一度に読み書きすることも悪影響です。 大きなデータセットの場合、データをシステムメモリに出し入れするためのオーバーヘッドが、読み取り/書き込み関数を呼び出す回数を減らすことで減らせるオーバーヘッドよりも大きくなります。 データセットをどれだけ大きくしたときに、これが制約要因になるかは、システムに依存し、システムに搭載されいる物理メモリの量により異なります。 これらの問題は、各読み取り/書き込み呼び出しで、合計バッファサイズの1/10から1/4を読み取る/書き込むようにすることで、多くのアプリケーションで回避できます。
ストリームのデータタイプは、ネットワーク経由でデータを送受信するときにデータを平坦化/非平坦化するために読み取り/書き込み関数にかかる作業量に影響を与えます。 このため、一般に、複雑なデータタイプのスループットは、簡単なデータタイプよりも劣ります。 特定のデータタイプの要素を転送するのに必要な作業量は、以下の要因で決まります。
1. データタイプの複雑さとサイズ。 たとえば、クラスタのようなデータタイプは、副要素として他のデータタイプを含み、ネストレベルも任意であるため、決まった構造をもつデータタイプよりも構文解析やコンストラクトするのに作業を要します。
2. データタイプの要素を格納するために必要なメモリをストリームエンドポイントが効率的に管理できる度合い。 データタイプが固定の場合、エンドポイントは全要素を連続したメモリブロックに格納できます。 データタイプが可変長の場合、エンドポイントは複数のメモリブロックを管理し、ランタイムには適宜、メモリの割り当てと解放を行う必要があります。
これらの条件から、最も効率的なのはスカラデータタイプであり、その単純さと固定サイズであることから最高のスループットを実現できます。 次にスループットが良いのは、サイズは異なるが単純と分類されるデータタイプです。 これには、スカラおよび文字列の配列が含まれます。 最後に、サイズも異なり、データ階層も複雑なクラスタやクラスタの配列などのデータタイプのスループットは最も劣ります。 最高のスループットを得るには、可能な限り、スカラデータタイプを使用することをお勧めします。
デフォルトでは、ネットワークストリームは、妥当なレイテンシを維持しつつ、ネットワーク帯域幅をできる限り効率的に使用するようにデザインされます。 これは、データがストリーム に書き込まれたときに、ストリームがそのデータをネットワークに送信する前に、一定時間保持する場合があることを意味します。 その目的は、小さな複数のパケットをネットワークに送信するのではなく、連続する複数の書き込みデータを結合して1つの大きなTCPパケットとして送信するためです。 ストリームがデータを送信するまでに待機する時間を決めるヒューリスティックは、保留中のデータ量とは関係なく、実装に依存するため、リリースごとに変化する可能性があります。 これは、TCPパケットオーバーヘッドにより、無駄になる帯域幅を最小化するには役立ちますが、低スループットデータストリームのデフォルトレイテンシを増加させます。 ストリームを使用して2つのアプリケーション間でコマンドを送受信している場合、レイテンシが増加するのは、望ましくありません。 この問題を緩和するために、書き込み関数を呼び出した直後に、下図のように排出関数を呼び出すことができます。
排出関数のタイムアウトを0にすることにより、書き込みエンドポイントは、読み取りエンドポイントから受信または読み取られたデータを待たずに、全データを読み取りエンドポイントに即時に送信します。 このプログラミング技法により、書き込みアプリケーションの実行をブロックせずに、最小のレイテンシでデータを送信できます。
ネットワークストリームは、ネットワーク経由でポイントツーポイント通信を行うときの新しいレベルの使いやすさを実現しますが、アプリケーションによっては、ネットワークストリームの使用が適さない場合もあります。
一般的に、ネットワークストリームは、制御アルゴリズム内での使用には適しません。 イーサネットは、通常、制御アプリケーション向けに信頼できる通信バスではなく、ストリームへの読み書きは確定的ではありません。 制御アプリケーション内でリモートHMIとの通信用にネットワークストリームが使用することはできますが、タイムクリティカルなループ内では使用しないでください。 制御アプリケーションのタイムクリティカルループと通信ループ間の通信には、その代わりにRT FIFOを使用する必要があります。 その時点で、制御アプリケーションの通信ループとリモートHMI間でデータを交換するためにネットワークストリームを使用できます。
ネットワークストリームは、ロスレスのポイントツーポイント通信用に設計されています。 これは、データストリーミングとコマンドベースのアプリケーションではうまく動作しますが、任意のN:1または多対多通信パスを確立することは非常に困難です。 これは、多くのクライアント/サーバアプリケーションで一般的な要件です。 同様に、ストリームでは読み取り後に書き込まれた最後の値は保持されないので、アプリケーションを監視したり、HMI上の制御器/表示器を更新するために使用するのは、より困難です。 これらのタイプのアプリケーションでは、他の通信方法が適切です。 アプリケーションに最適な通信方法の選択については、「Using the Right Networking Protocol」のチュートリアルを参照してください。
最後に、アプリケーションで最高のネットワークスループットを得たい場合には、ネットワークストリームではなく、TCP APIを使用中することが望ましい場合があります。 TCPを使用すると、ネットワークに送信するデータを詳細に制御でき、通信をアプリケーションに最適にカスタマイズすることが可能です。 同様に、同じLabVIEWアプリケーションコンテキスト内のエンドポイント間の通信にネットワークストリームを使用する場合、最適なパフォーマンスを得るために、キューを使用することをお勧めします。 通信は同じメモリコンテキスト内で発生するので、キューは1つのメモリバッファしか使用しません。 このため、エンドポイントがホストされている場所に関係なく、2つのエンドポイントバッファに依存するネットワークストリームよりも、よいパフォーマンスが得られます。
LabVIEW 2010の時点で、ネットワークストリームは、Microsoft WindowsまたはLabVIEW Real-Timeが稼動するターゲットでのみサポートされています。 Microsoft Windowsの場合、ネットワークストリームはLabVIEWベースバッケージに含まれているので、インストールと同時に使用できます。 Windowsのファイアウォール設定でネットワークストリームを使用する方法については、技術サポートデータベース 5BCF43RY:「Recommended Firewall Settings When Using Network Streams」を参照してください。
LabVIEW Real-Timeターゲット用にアプリケーションを開発するためのネットワークストリームのサポートは、LabVIEW Real-Timeモジュールを開発用コンピュータにインストールする際に、自動的に含まれます。 しかし、Measurement & Automation Explorerからリアルタイムターゲットにソフトウェアをインストールするとき、ネットワークストリームは、デフォルトでは含まれていません。 LabVIEW Real-Timeターゲットでネットワークストリームを有効にするには、インストール時に下図のように、ネットワークストリーム機能が選択されていることを確認してください。
リアルタイムターゲットからソフトウェアセットが提示される場合、それにネットワークストリームが含まれている場合も含まれていない場合もあります。 この機能がソフトウェアセットに含まれていない場合は、この機能が含まれている別の推奨ソフトウェアセットを選択するか、カスタムソフトウェアインストールオプションを選択してください。
パフォーマンス期待値に関するガイドを提供するために、さまざまなターゲットで実行したときのスループット、レイテンシ、CPU使用率を測定するベンチマークを数回行いました。 すべてのベンチマークは、孤立したギガビットネットワークで実施しました。 通信に関与するターゲットのいずれかが1 Gb/sネットワークインタフェースをサポートしない場合、ネットワーク接続は、自動的に100 Mb/sでネゴシエートされます。 ベンチマークで使用される各ターゲットの仕様の概要的な要約を下表に示します。
コントローラ |
プロセッサ |
メモリ |
ネットワークインタフェース |
ソフトウェア |
デスクトップコンピュータ | Intel Xeon Quad-Core W3520、2.66 GHz |
6 GB |
1 Gb/sイーサネットアダプタ |
Windows 7(64ビット) LabVIEW 2010(32ビット) |
NI PXI-8106 | Intel Core 2 Duo 2.16 GHz |
1 GB |
1 Gb/sイーサネットアダプタ | LabVIEW Real-Time 2010 |
NI cRIO-9012 | 400 MHz Freescale MPC5200 |
64 MB |
100 Mb/sイーサネットアダプタ | LabVIEW Real-Time 2010 |
NI cRIO-9024 | 800 MHz Freescale MPC8377 |
512 MB |
1 Gb/sイーサネットアダプタ | LabVIEW Real-Time 2010 |
特に表記がない場合、すべてのベンチマークは、エンドポイントの少なくとも1つがデスクトップPCターゲットで実行されている状態で実施しました。 また、LabVIEW RTをSMPで使用しているPXI-8106のネットワークパフォーマンスを最大化するために、RT SMP CPUユーティリティVIを使用して、システムプロセスはすべて強制的にコア0で実行し、タイミングストラクチャはすべて強制的にコア1で実行しました。
スループットベンチマークは、ストリームへの各読み取り/書き込み呼び出しで一定数の倍精度データ要素をネットワークに転送して実施しました。 読み取り/書き込み関数はループ内に配置し、CPUとネットワークの上限速度で実行しました。 次に、読み取りエンドポイントで60秒間にストリームから読み取られた要素数を合計することで、スループットを計算しました。 ターゲットからデータを主に読み取るか、書き込むときに見られるパフォーマンスの違いを定量化するために、ストリームの方向を切り替えて、これらの測定を繰り返しました。
スループットを最適化するときに実現可能なスループットに最も影響があるのは、エンドポイントバッファサイズと各読み取り/書き込み呼び出しで読み取られる/書き込まれる要素数です。 これらのパラメータの影響度を調べるために、2つのテストを実施しました。 最初のテストは、さまざまなバッファサイズをスイープして、読み取り/書き込みサイズをバッファサイズの1/10に固定します。 2番目のテストは、最初のテストで求めた最適バッファサイズを使用して、さまざまな読み取り/書き込みサイズをスイープします。 比較用に、ネットワークストリームAPIの代わりにTCP関数を使用して2番目のテストを繰り返しました。 これらの結果が以下です。
* ストリームエンドポイントのバッファサイズ = 1,000,000 要素
* ストリームエンドポイントのバッファサイズ = 1,000,000 要素
* ストリームエンドポイントのバッファサイズ = 500,000 要素
レイテンシベンチマークは、2つのストリームを使用して2つのターゲット間に双方向通信リンクを形成することで実施しました。 ターゲット1からのコマンドを書き込み、ターゲット2からのコマンドを読み取り、ターゲット1にコマンドをエコーバックし、ターゲット1からコマンドを読み取るまでの往復トリップ時間を測定しました。 レイテンシを最小化するために、各書き込み関数の後で排出関数を呼び出しました。 このテストシーケンスを10,000回繰り返し、結果時間を平均してから、片道通信の平均レイテンシを求めるために2で割りました。 マイクロ秒の分解能を得るとともに、計測ジッタを最小化するために、測定はLabVIEW Real-Timeシステム上で行いました。 転送メカニズムとしてネットワークストリームの代わりにTCPを使用して、同様のテストを実施しました。 結果は以下の表に記載されています。
ターゲット |
接続 |
TCP (µs) |
ネットワークストリーム (µs) |
PXI-8106 |
1 Gb/s |
82.02 |
347.90 |
cRIO-9024 |
1 Gb/s |
268.13 |
630.59 |
cRIO-9012 |
100 Mb/s |
508.48 |
1581.25 |
可能な最大スループットを得るには、CPUの大部分を消費することが必要な場合が多くあります。 多くの場合、これは望ましくありません。 この代わりに、CPUの全体使用率の一定割合を超えずに得られる最大スループットを求めることのほうが有用な場合が多いです。 この情報を得るために、各ターゲットに関して、スループットとCPU使用率の間の傾向線を作成するために、一連のベンチマークを行いました。 これらの実験結果を以下のグラフに示します。
これらのグラフは、指定レートで書き込み、平均CPU使用率とスループットを測定して、作成しました。 与えられたスループットレートに関して、書き込みエンドポイントは、目的のスループットを得るために必要な間隔で固定サイズのデータを書き込むことで、一定ののスループットを生成しようとします。 データは、次にこのターゲットレートで60秒間転送され、データ転送の間、0.5秒おきにCPU使用率を測定しました。 60秒間隔の終わりに、CPU使用率を平均化して、読み取りエンドポイントで実際のスループットを計算しました。 次に、ターゲットスループットを増加して、CPU使用率の測定値が90パーセントを超えるか、スループット測定値が横ばい状態になるまで繰り返しました。 使用するバッファサイズと、繰り返しごとの読み取り/書き込み要素数は、前のテストの最適結果に基づいて選択しました。 この場合も、比較用に、ネットワークストリームの代わりにTCPを使用した結果を出しました。
* ストリームのバッファサイズ = 1,000,000 要素、ストリームの読み取り/書き込みサイズ = 100,000 要素、TCP読み取り/書き込みサイズ = 10,000 要素
* ストリームのバッファサイズ = 1,000,000 要素、ストリームおよびTCPの読み取り/書き込みサイズ = 100,000 要素
* ストリームのバッファサイズ = 500,000 要素、ストリームおよびTCPの読み取り/書き込みサイズ = 50,000 要素