2011-12-31 6 views
1

私のCプログラムは、Linux上のTCPソケットから数バイト(のread(2)またはrecv(2))を読み取りました。これらのバイトをプッシュして、後でread(2)recv(2)コール(私が制御していないライブラリの内部に発行されている)が再びそれらを読み込むことは可能ですか?BSDソケットを未読(unget)しましたか?

私はのrecv(2) MSG_PEEKフラグについて知っている、と私は戻ってプッシュすることは不可能であることが判明した場合、回避策として、それを使用するつもりです。

+4

あなたのアプリケーション内のバッファリングでは、Linuxカーネルにそれを要求しないでください。 –

+0

@Basile Starynkevitch:私のユースケースではあなたの提案は不可能です。 *私が制御していない図書館の中で深く発行された*の題を見てください。 – pts

+0

"recv" APIへの呼び出しを制御すると、(なぜBasileが言ったように)自分のバッファリング層でこれらの呼び出しをラップできないのですか?あなたがrecv呼び出しにMSG_PEEKを渡す能力を持っているなら、あなたはrecvの上に独自のラッパーを実装できるはずですか?右? – selbie

答えて

2

私が求めていることは不可能だと思われます。私はフラグMSG_PEEKでrecv()を呼び出し終わった。これにより、ライブラリーの後続のrecv()またはrecvmsg()呼び出しが同じデータを読み取るようになります。

他の呼び出しがなければ、私は便宜上、1バイトだけを先読みするために使用できます。 2バイト先読みが必要だとしましょう。私はrecv(fd, buf, 2, MSG_PEEK)と呼ぶだろう。 2バイトのうち1バイトがすでに到着していれば、何回呼び出してもrecvは直ちに戻ります。私はepoll_ctlEPOLLIN | EPOLLETを使用して2番目のバイトを待つことができます。その後、EOFがあるかどうかを知りたい場合はEOPLLIN | EPOLLET | EPOLLRDHUPが必要です。 (EPOLLHUPはEOFで返されませんのでご注意ください)epoll_ctlを使用すると、ビジー状態のポーリングループでrecvを呼び出して2番目のバイトを読み取ることを避けることができます。

私はLinuxシステム上で、デフォルトでこの方法で約900 kBのソケットを確認できることを確認しました。 (SO_RECVBUFは、デフォルトでは私のために1メガバイトであるのsetsockoptでそれを減らすを受信することができますどのくらい減少するようではなく、一貫性のある量だけ。たぶん私は遅すぎるそれを減らす?)MSG_PEEK

でも組み合わせとEPOLLETは、未解決のバイトをソケットに未読で残さないため、回避策です。彼らが私にさせてもらうのは、すでに到着したバイトを消費することなく覗くことです。

+1

EPOLLET(エッジトリガー)モードのepollにfdを追加してNバイトを待つことができるかもしれません。もしあなたがrecvを気に入らなければ、次のepollイベントを待ってからrecvを再試行してください。 – anthonyrisinger

+0

@anthonyrisinger:EPOLLETを提案してくれてありがとう、それはあなたがそれを説明したように動作します。 – pts

2

最適なオプションは、ワークフローを変更して、データを読み込んだ後に戻す必要がないようにすることです。ちょうど2回何かを読むのはちょっと醜いようです(私はそれが合法かもしれないことに同意します)。

しかし、これは非常に難しいことができない場合、または、あなたはLD_PRELOADを使用してreadrecvシステムコール(dlsym)を乗っ取ることができます。

+0

+1、うわー、私はLD_PRELOADについて聞いたことがありません。それが存在することを知ってよかったです(しかし、私はあなたに最高のオプションについて同意します)。 –

+0

'LD_PRELOAD'を提案していただきありがとうございます。しかし、私の場合、出力は静的にリンクされたバイナリでなければならないので、 'LD_PRELOAD'は何の違いもありません。 – pts

+0

@ptsリンカーのトリックにはあまり経験はありませんが、自分のシンボルを呼び出すためにそのライブラリを欺くことはできませんか? – cnicutar

関連する問題