1

TCP ソケットを介して送信されるいくつかの XDR データ パケットがあります。ここに私のコードのスニペットがあります:

const size_t BUFFER_LENGTH = 2000;
XDR xdr;
char *buffer = new char[BUFFER_LENGTH];
xdrmem_create(&xdr, buffer, BUFFER_LENGTH, XDR_ENCODE);

const std::string requestId = request->getPacket()->getRequestId();
MyPacket responcePacket(requestId, status,message);
responcePacket.serialize(&xdr);

unsigned int byteSent = write(*socketDescriptor_, buffer, BUFFER_LENGTH);
delete buffer;
if(byteSent!=BUFFER_LENGTH)
{
    throw Exception("Error during write!");
}

ここで、パケットは次のようにシリアル化されます。

class MyPacket:

    void MyPacket::serialize(XDR* xdr)
    {
        // Convert Enum to int
        int _messageType = (int) messageType_;
        uint32_t _status = (uint32_t) status_;

        //Copy all strings to c_string
        char *_requestId = new char[requestId_.length() + 1];
        std::strcpy(_requestId,requestId_.c_str());

        char *_message = new char[message_.length() + 1];
        std::strcpy(_message,message_.c_str());

        bool status = xdr_int(xdr, &_messageType) &&
                    xdr_string(xdr, &_requestId, REQUESTID_LENGTH_) &&
                    xdr_u_int(xdr, &_status ) &&
                    xdr_string(xdr, &_message, MESSAGE_LENGTH_);

        delete _requestId;
        delete _message;

        if(!status)
        {
            throw new Exception("Error while serializing MyPacket.");
        }
    }

....

}

最初のテストとして、最大パケット サイズが 2000 であると想定しており、反対側からは常に 2000 を読み取っています。最初のテストとして、これは問題なく動作しますが、必要でないときはより少ない情報を送受信できるようにしたいと考えています。さらに、サーバーのパケット サイズを増やした場合に備えて、クライアントを再コンパイルする必要はありません。

自分でパケット サイズを付加せずに、このストリームを送受信する適切な方法があるかどうかを知りたいです。そして、これを自分で追加する必要がある場合、xdr サイズを簡単に取得する方法はありますか?

乾杯、

追加: 次のように xdr_rec バッファーを使用してみました。

XDR ixdr;
int i;
xdrrec_create (&ixdr,0,0,reinterpret_cast<char*> (&ui),&underflow,0);
ixdr.x_op = XDR_DECODE;

cout << "xdrrec_eof: " << xdrrec_eof (&ixdr) <<endl;
cout << "xdrrec_skiprecord: " << xdrrec_skiprecord (&ixdr) <<endl;

for(j=0;j<10;j++){
    xdr_uint32_t (&ixdr, &i);
    cerr << "i: " << i << endl;
}xdr_destroy (&ixdr);

10 uint32 の正しいバッファをフィードすると、すべてうまくいきます。ここで、バッファーの最後でいくつかのバイトをカットしようとしましたが、xdrrec_eofまたはxdrrec_skiprecordエラーが発生することを期待していました。これは、まだすべてのデータを受信して​​いないことを検出するために使用したかったものです。代わりに、両方が成功して戻りxdr_uint32_t、コードの実行がブロックされます。したがって、今でも本当に見逃しているのは、でデコードを開始する前に完全なパケットを受信したことを検出する方法xdr_uint32_tです。なにか提案を?

4

1 に答える 1

1

パケットサイズは関係ありません。XDR ライブラリが読み取りを要求したときに、読み取る必要があります。XDRxdr_recストリーム タイプは、長さワードを含むストリームを処理します。あなたがしなければならないのは、独自の読み取りおよび書き込み関数を提供することだけです。これをやったのは22年ぶりですが、難しくはありませんでした。「デコードを開始する前に完全なパケットを受信する」必要があると考える理由がわかりません。あなたはそうしない。必要に応じて関数xdr_recを呼び出します。read()

問題は、 xdr_uint32_t がブロックしていることです

いいえ。XDR 関数はブロックしていません。それらの1つではありません。ソースを読んでください。read()ブロックする機能です。

したがって、同じスレッドに読み取りと xdr_uint32_t があり、ストリーム全体の読み取りが完了する前に xdr_uint32_t を実行した場合

それは意味がありません。私が上に書いたことを読んでください。「XDR ライブラリーから読み取りを要求されたら、読み取る必要があります。」前ではありません。

これにより、アプリケーションがブロックされるリスクがあります。したがって、おそらくソケットの読み取りとデコードを2つの別々のスレッドで行う必要があります。

いいえ、あなたは仕組みを理解していないようですxdr_rec。オブジェクトを作成し、xdr_recそれに読み取りコールバック関数と書き込みコールバック関数を提供します。そこから、好きな XDR ルーチンを呼び出すだけで、必要に応じ読み取りコールバックまたは書き込みコールバックが呼び出されます。あなたはそれらをまったく呼びません。最初に「ストリーム全体を読み取る」必要はありません。

これらすべてを 1 つのスレッドで実行する必要があります。

于 2016-03-17T10:02:59.153 に答える