2016-07-18 20 views
3

ドメインソケットを使用してsendmsgrecvmsgを使用して2つのプロセス間でファイル記述子を渡すプログラムを作成しています。ファイル記述子を送信するために、追加データはmsghdr.msg_iovmsghdr.msg_iolenに含まれています。しかし、私は、通常のreadwriteシステムコールと同様に、sendmsgrecvmsgも部分的な読み取り/書き込みの問題があることを知っていました。この場合、補助データのデータは部分データごとに自動的に複製されますか?実装にはノンブロッキングメカニズムが必要なので、私はこれを求めています。私はもう少しsendmsg/recvmsgの部分的な読み取り/書き込みの問題

送信者を、それを詳しく説明するために、次の例を使ってみましょう:(1)部分的な読み取り、K1バイト(2):補助的なフィールドでfdが含まmsghdrデータとmsg_iov

レシーバでKバイトを送信K-K1バイト

上記の例のように、実際にすべてのデータが到着した段階(2)の後にデータを処理する必要があります。この場合、補助フィールドからfdを正しく抽出できますか?それとも、最初の部分的な読み込みにのみ表示されますか?

+0

'sendmsg()'が返す値を示すバイト数だけ送信し、 'recvmsg()'が返す値を示すバイト数だけ受信します。どちらの場合も、完全な送受信を確実にするためにループする必要があります。 – EJP

+0

私はこれを知っています。私は実際に補助的なデータを求めています。この部分読み取り/書き込みの場合はどうなりますか – Jes

+1

2つの異なるプロセス間でファイル記述子を送信できません。ファイルディスクリプタは、ポインタと同様に、プロセスにとってローカルです。 –

答えて

0

カーネルソース(Linux、しかし以下を参照)で素早く逃げ出しているので、補助データが一度だけ送られることを確認するのはあなた次第です。つまり、非ブロックモードでは、受信ソケットに空きがなければ、EAGAIN/EWOULDBLOCKが返され、データも補助データも送信されません。しかし、受信側にスペースがあれば、データの最初の部分が送信され、補助データも送信されます。その後、部分的な送信を示す戻りバイト数が返されますが、補助データは送信されます。

カーネルは以前に、後続のバッファが論理的に連続している部分バッファを送信したというメモリを保持していないので、残りのメッセージを送信しようとすると気付く必要がありますあなたが知っているすべてのデータをまったく別のものに送ることができます)。したがって、後続のバッファ部分に同じ補助データを提供するだけであれば、カーネルは後続のバッファ部分で補助データを再送することができます。これにより、受信者側にファイル記述子が重複する可能性があります(これを避けていないと、あなたが期待していなかったため、おそらく閉じてしまうでしょう)。

送信側でブロックモードになっていて、転送が複数の部分に分割されている場合、バッファ全体の送信が残っているため、補助データは最初のバッファ部分で1回だけ送信されますカーネル制御内で実行されます。

受信側では、論理メッセージ全体を受信して​​いない場合は、受信したデータの最初のチャンクに付随するデータが付随することに注意する必要があります。

この動作は、@ Klas-Lindbäck(https://unix.stackexchange.com/questions/185011/what-happens-with-unix-stream-ancillary-data-on-partial-reads)によって与えられたstackexchangeリファレンスで報告されている動作と一貫していると思います。 (その質問はノンブロッキングモードを扱っていませんでした)

この回答はLinuxに固有のものです。したがって、他のOSで結果がわずかに異なる可能性は確かですが、それがどのように大きく異なるのかを確認するのは難しいですが、依然として正常なセマンティクスを維持できません。カーネルは以前に送信されたもののメモリを合理的に維持することができず、sendmsgプロトタイプはユーザのmsghdrを上書きして、msg_controlの部分がすでに送信されたことを反映することはできません。

関連する問題