Хороший способ отправки XDR через сокет TCP

У меня есть некоторые пакеты данных XDR, которые отправляются через сокет TCP.
Вот фрагмент моего кода:

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, Любое предложение?

1

Решение

Размер пакета не имеет значения. Вам просто нужно прочитать, когда библиотека XDR попросит вас прочитать. XDR xdr_rec Тип потока имеет дело с потоками с длиной слова в них. Все, что вам нужно сделать, это снабдить его собственными функциями чтения и записи. Прошло 22 года с тех пор, как я это сделал, но это было не сложно. Я не понимаю, почему вы думаете, что вам нужно «получить полный пакет перед началом [ing] декодирования». Вы не xdr_rec позвоню вашему read() функционировать так часто, как это необходимо.

Проблема в том, что xdr_uint32_t блокирует

Нет. Функции XDR не блокируются. Ни один из них. Прочитайте источник. Это read() функция, которая блокирует.

так что если у меня есть чтение и xdr_uint32_t в том же потоке, и я запускаю xdr_uint32_t, прежде чем закончить чтение всего потока

Это не имеет смысла. Прочитайте то, что я написал выше. «Вам просто нужно читать, когда библиотека XDR просит вас прочитать». Не раньше, чем.

это рискует заблокировать приложение. Так что, вероятно, мне нужно иметь сокет чтения и декодирования в 2 отдельных потока.

Вы, кажется, не понимаете, как xdr_rec работает. Вы создаете xdr_rec объект и предоставить ему функцию обратного вызова чтения и функцию обратного вызова записи. Оттуда вы просто вызываете любые подпрограммы XDR, которые вам нравятся, и Oни вызывайте обратные вызовы read или write в зависимости от ситуации. Вы не звоните им вообще. Нет необходимости сначала читать весь поток.

Вы должны сделать все это в одном потоке.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]