部分的な読み取りでUNIXストリームの補助データはどうなりますか?


18

UNIXストリームの補助データに関する多くの情報を読みましたが、すべてのドキュメントから欠落していることの1つは、部分的な読み取りがある場合に何が起こるかということです。

24バイトのバッファーに次のメッセージを受信するとします。

msg1 [20 byes]   (no ancillary data)
msg2 [7 bytes]   (2 file descriptors)
msg3 [7 bytes]   (1 file descriptor)
msg4 [10 bytes]  (no ancillary data)
msg5 [7 bytes]   (5 file descriptors)

recvmsgの最初の呼び出しで、msg1のすべて(およびmsg2の一部を取得しますか?OSはこれを実行しますか?)メッセージが実際にデータを処理するように言っていることを知っているとき?msg1から20バイトを解放してからrecvmsgを再度呼び出すと、msg3とmsg4を同時に配信しますか?msg3およびmsg4からの補助データは、制御メッセージ構造体で連結されますか?

これを実験的に調べるためのテストプログラムを作成することはできますが、ストリーミングコンテキストでの補助データの動作に関するドキュメントを探しています。公式なものが見つからないのは奇妙に思えます。


このテストプログラムから得た実験結果をここに追加します。

https://github.com/nrdvana/daemonproxy/blob/master/src/ancillary_test.c

Linux 3.2.59、3.17.6

このrecvmsgの呼び出し中に事前の補助ペイロードを配信する必要がない限り、Linuxは補助ベアリングメッセージの一部を他のメッセージの最後に追加するようです。1つのメッセージの補助データが配信されると、次の補助データメッセージを開始するのではなく、短い読み取りを返します。したがって、上記の例では、取得する読み取りは次のとおりです。

recv1: [24 bytes] (msg1 + partial msg2 with msg2's 2 file descriptors)
recv2: [10 bytes] (remainder of msg2 + msg3 with msg3's 1 file descriptor)
recv3: [17 bytes] (msg4 + msg5 with msg5's 5 file descriptors)
recv4: [0 bytes]

BSD 4.4、10.0

BSDはLinuxよりも多くの整合性を提供し、補助データを含むメッセージの開始直前短い読み取りを行います。しかし、補助的なメッセージの最後に非補助的なメッセージを喜んで追加します。したがって、BSDの場合、バッファが補助的なメッセージよりも大きい場合、ほとんどパケットのような動作をするように見えます。私が得る読み取りは次のとおりです。

recv1: [20 bytes] (msg1)
recv2: [7 bytes]  (msg2, with msg2's 2 file descriptors)
recv3: [17 bytes] (msg3, and msg4, with msg3's 1 file descriptor)
recv4: [7 bytes]  (msg5 with 5 file descriptors)
recv5: [0 bytes]

TODO:

古いLinux、iOS、Solarisなどでどのように発生するのか、今後どのように発生することが予想されるのかを引き続き知りたいです。


ストリームとパケットを混同しないでください。ストリームでは、データが送信されたのと同じチャンクで配信されるという保証はありません。このため、ストリームベースではなくパケットベースのプロトコルが必要になります。
ctrl-alt-delor

それは、なぜ私はこの質問を求めている正確だ
Mコンラッド

順序は保持する必要があります。それがストリームの機能です。ブロッキング読み取りが0を返す場合、それはストリームの終わりです。別の数値が返される場合、さらに多くの数値が存在する可能性があるため、少なくとも1回は読み取りを行って確認する必要があります。message1、message2などはありません。メッセージ区切り文字は送信されません。必要に応じて、これをプロトコルに追加する必要があります。
ctrl-alt-delor

1
具体的には、テキストストリームプロトコルを使用しており、ファイル記述子とテキスト行を渡すコマンドを追加しています。コードを適切に記述するためには、メッセージのテキストに対してこの補助データが受信される順序を知る必要があります。
Mコンラッド

1
@MConrad:POSIX.1g仕様のコピーを入手しようと思います。明示的に記述されていない場合、実装固有の動作が期待されます。
ラスロヴァルコ

回答:


1

補助データは、セグメント内の最初の通常のデータオクテット(存在する場合)と共にキューに入れられたかのように受信されます。

- POSIX.1-2017

あなたの質問の残りの部分については、物事は少し毛深いです。

...このセクションの目的上、データグラムはレコードを終了するデータセグメントと見なされ、特別なタイプの補助データとして送信元アドレスが含まれます。

プロトコルによってデータがソケットに配信されると、データセグメントがキューに配置されます。通常のデータセグメントは、配信時にキューの最後に配置されます。新しいセグメントが前のセグメントと同じタイプのデータを含み、補助データを含まない場合、および前のセグメントがレコードを終了しない場合、セグメントは論理的に単一のセグメントにマージされます...

受信操作は、複数のセグメントからデータまたは補助データを決して返さないものとします。

そのため、最新のBSDソケットはこの抽出と完全に一致します。これは驚くことではありません:-)。

POSIX標準は、UNIXの後に、BSDとSystem Vのような分割の後に書かれたことを思い出してください。主な目標の1つは、既存の動作範囲を理解し、既存の機能のさらなる分割を防ぐことでした。

Linuxは、BSDコードを参照せずに実装されました。ここでは異なる動作をするようです。

  1. 正しく読んだ場合、新しいセグメントに補助データ含まれているが、前のセグメントには含まれていないときに、Linuxが「セグメント」を追加でマージしているように聞こえます。

  2. 「recvmsgの呼び出し中に事前の補助ペイロードを配信する必要がない限り、Linuxは補助ベアリングメッセージの一部を他のメッセージの最後に追加します」という点は、標準では完全に説明されていないようです。1つの可能な説明には、競合状態が含まれます。「セグメント」の一部を読むと、補助データを受け取ります。おそらくLinuxはこれを、セグメントの残りの部分が補助データを含むものとしてカウントしないことを意味すると解釈しました!したがって、新しいセグメントが受信されると、標準に従って、または上記の差分1に従ってマージされます。

移植性の高いプログラムを作成する場合は、この領域を完全に回避する必要があります。補助データを使用する場合、データグラムソケットを使用するのが一般的です。技術的にPOSIXのようなものを提供することを熱望する奇妙なプラットフォームすべてで作業したい場合、あなたの質問は暗くてテストされていないコーナーに向かっているようです。


Linuxはまだいくつかの重要な原則に従っていると言えます。

  1. 「補助データは、セグメント内の最初の通常のデータオクテットとともにキューに入れられたかのように受信されます」。
  2. あなたがそれを置くように、補助データは決して「連結」されません。

ただし、BSDの動作と比較すると、Linuxの動作が特に役立つとは思いません。説明したプログラムは、Linux固有の回避策を追加する必要があるようです。そして、Linuxがあなたにそうすることを期待する理由の正当性は知りません。

Linuxカーネルコードを記述するときは賢明に見えたかもしれませんが、プログラムによってテストまたは実行されたことはありません。

または、このサブセットの下でほとんど動作するプログラムコードによって実行されるかもしれませんが、原則としてエッジケースの「バグ」または競合状態を持つことができます。

Linuxの動作とその使用目的を理解できない場合は、これをLinuxの「テストされていない暗いコーナー」として扱うことをお勧めします。


詳細なレビューをありがとう!ここでのポイントは、2つのバッファ(それぞれデータ部分と補助部分)でこれを安全に処理できることだと思います。最初の読み取りでファイル記述子を受信し、それらがメッセージに属していないが、別のメッセージが始まる場合、次の読み取りにも補助データが含まれている場合、最初の補助ペイロードを所有するデータメッセージの終わりを間違いなく見つけることを意味しますその2番目の読み取りで。交互に行って、最初のバイトの位置に基づいて、常にメッセージとペイロードを一致させることができるはずです。
Mコンラッド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.