2012-09-22 16 views
6

2つのアプリケーション間でシリアル化されたデータ構造を送信するために、データを1バイトストリームとして送信するように構成された名前付きパイプを使用しています。シリアライズされたデータのサイズはかなり大きく変化します。送信側では、これは問題ではありません。正確に送信するバイト数を調整できます。Named Pipes、読み取り側で読み取る正確なバイト数を知る方法。

受信側(読み取り側)のバッファを正確に読み取るバイト数に設定するにはどうすればよいですか?送信側(書き込み側)のデータがどれだけ大きいかを知る方法はありますか?

私はPeekNamedPipeを見ましたが、この関数はバイト型の名前付きパイプでは役に立たないと思われますか? このメッセージに残っているバイトの数を受け取る変数へのポインタ

lpBytesLeftThisMessage [、オプションのうち]。このパラメータは、バイト型の名前付きパイプまたは匿名パイプの場合はゼロになります。このパラメータは、読み込むデータがない場合はNULLにすることができます。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx

あなたが正確に必要なバッファサイズを決定することができない場合はどのように1は最高のこのような状況を処理しますか?

送信コード

string strData; 
strData = "ShortLittleString"; 

DWORD numBytesWritten = 0; 
result = WriteFile(
    pipe, // handle to our outbound pipe 
    strData.c_str(), // data to send 
    strData.length(), // length of data to send (bytes) 
    &numBytesWritten, // will store actual amount of data sent 
    NULL // not using overlapped IO 
); 

読み出しコード:バッファ上記のコードで

DWORD numBytesToRead0 = 0; 
DWORD numBytesToRead1 = 0; 
DWORD numBytesToRead2 = 0; 

BOOL result = PeekNamedPipe(
pipe, 
NULL, 
42, 
&numBytesToRead0, 
&numBytesToRead1, 
&numBytesToRead2 
); 

char * buffer ; 

buffer = new char[numBytesToRead2]; 

char data[1024]; //1024 is way too big and numBytesToRead2 is always 0 
DWORD _numBytesRead = 0; 

BOOL result = ReadFile(
pipe, 
data, // the data from the pipe will be put here 
1024, // number of bytes allocated 
&_numBytesRead, // this will store number of bytes actually read 
NULL // not using overlapped IO 
); 

は常にPeakNamedPipe関数としてサイズ0のすべてnumBytesToRead変数に0を返し。このバッファサイズを正確に設定する方法はありますか?そうでない場合、そのような状況を処理する最善の方法は何ですか?助けてくれてありがとう!

+0

単純なアプローチは、その後、最初のデータの長さを記述することです。レシーバは、最初に長さを簡単に読み取ってバッファを割り当てることができます。パイプメッセージモードの仕組みと変わりはありません。 –

答えて

1

まあ、あなたはReadFile()を使用しています。ドキュメントは、とりわけ、こう述べています。

名前付きパイプをメッセージモードで読まれていると、次のメッセージが長い nNumberOfBytesToReadパラメータ指定を超える場合、ReadFile関数は、ERROR_MORE_DATAを返すGetLastErrorをFALSEを返し、 。メッセージの残りの部分は、後でReadFileまたはPeekNamedPipe関数を呼び出すことによって と読むことができます。

これを試しましたか?私はこのようなパイプを使ったことはありません:-)、子プロセスのstdin/outハンドルに到達するためにしか使用しませんでした。

私は、上記のことが必要なだけ頻繁に繰り返され、「メッセージの残りの部分」がいくらか正確ではないことを前提としています。「残余」があなたのバッファに収まらない場合、 ERROR_MORE_DATAをもう一度取得して、残りの部分を取得するようにしてください。

もし私があなたを完全に誤解していて、実際にこの「メッセージモード」を使用していないのであれば、間違ったことを読んでいるだけかもしれません。データの終わりに達するまで、固定サイズのバッファを使用して最終ブロックにデータを読み込んで追加することができます。または、これを少しでも最適化するには、「固定」サイズのバッファのサイズを増やしてください。

+0

いいえ私はしていません。これはちょっとしたハックのようですが、もう少しERROR_MORE_DATAエラーが出ないようになるまで、私は非常に小さなインクリメントとループで読むことを提案していますか? :)それはうまくいくはずですが、メッセージにデータサイズを追加したり、シリアル化されたデータに付加された無関係なデータで終わることは避けようとしています。テキストファイルを読むのと同じようにEOFまで読む方法はありませんか?自分のEOFを書き込み側に挿入することはできますか? – Rudolf

+0

私はメッセージモードを使用していません、私はバイトモードを使用しています。 :)しかし、私はあなたにちょうど私に考えを与えたと思う、私はバイトモードは、固定長文字を送信するときに使用されると思う、私はチョップし、システムをメッセージモードのパイプに変更し、報告する? – Rudolf

+0

バイトモードは、実装している使用例に対して、メッセージングプロトコルを管理するための責任を負いません。言い換えれば、メッセージパイプの一部はメッセージ長の属性です。 *あなたがそれを表すデータを送ることによってそれを管理しない限り、そのような属性はバイトモードでは存在しません。別の言い方をすると、メッセージモードは、どれくらい保持しているかを示すラベルが付いた箱をあなたに渡す男です。バイトモードはあなたに製品を投げている男です。あなたが本当に働くのに十分でない人の心に何があるのか​​分からなければ。 – WhozCraig

3

なぜあなたはlpTotalBytesAvailを送信データサイズに使用できなかったと思いますか?それは常にバイトモードで私のために働く。おそらくあなたは何か間違っていた可能性があります。また、データバッファーとしてstd::vectorを使用することをお勧めします。これは、生ポインタとnewステートメントを使用することよりも安全です。

lpTotalBytesAvail [out, optional]パイプから読み取ることができる合計バイト数を受け取る変数へのポインタ。このパラメータは、読み込むデータがない場合はNULLにすることができます。

サンプルコード:

// Get data size available from pipe 
DWORD bytesAvail = 0; 
BOOL isOK = PeekNamedPipe(hPipe, NULL, 0, NULL, &bytesAvail, NULL); 
if(!isOK) 
{ 
    // Check GetLastError() code 
} 

// Allocate buffer and peek data from pipe 
DWORD bytesRead = 0;  
std::vector<char> buffer(bytesAvail); 
isOK = PeekNamedPipe(hPipe, &buffer[0], bytesAvail, &bytesRead, NULL, NULL); 
if(!isOK) 
{ 
    // Check GetLastError() code 
} 
+0

lpTotalBytesAvailは私にとって素晴らしい仕事でした!これは、ハンス・パサントが提案したようにサイズを前にするために多くのトラブルや高価なバッファ・コピーを節約しました。 –

関連する問題