通过 TCP 套接字发送 XDR 的好方法

Good way for sending XDR over TCP Socket

我有一些通过 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_eofxdrrec_skiprecord 给我一个错误。这就是我想用来检测我还没有收到所有数据的东西。相反发生的是 return 成功和 xdr_uint32_t 阻止代码执行。所以我现在真正想念的是一种在使用 xdr_uint32_t 开始解码之前检测到我已经收到完整数据包的方法。有什么建议吗?

数据包大小无关紧要。当 XDR 库要求您阅读时,您只需要阅读。 XDR xdr_rec 流类型处理其中包含长度字的流。您所要做的就是为其提供您自己的读写功能。我这样做已经 22 年了,但这并不困难。我不明白为什么你认为你需要 'receive a full packet before start[ing] decoding'。你不知道。 xdr_rec 将根据需要经常调用您的 read() 函数。

The problem is that xdr_uint32_t is blocking

没有。 XDR 函数不阻塞。不是其中之一。阅读源代码。阻塞的是 read() 函数。

so if i have the read and the xdr_uint32_t in the same thread and i run xdr_uint32_t before having finished reading the whole stream

这没有意义。阅读我上面写的内容。 'You just have to read when the XDR library asks you to read.' 之前没有。

this risks to block the application. So probably i need to have the socket reading and the decoding in 2 separate threads.

没有。您似乎不了解 xdr_rec 的工作原理。您创建一个 xdr_rec 对象并为其提供一个读取回调函数和一个写入回调函数。从那里开始,您只需调用您喜欢的任何 XDR 例程,它们 会根据需要调用读取或写入回调。你根本不打电话给他们。没有要求先'read the whole stream'

你应该在一个线程中完成所有这些。