У меня есть некоторые пакеты данных 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
, Любое предложение?
Размер пакета не имеет значения. Вам просто нужно прочитать, когда библиотека 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 в зависимости от ситуации. Вы не звоните им вообще. Нет необходимости сначала читать весь поток.
Вы должны сделать все это в одном потоке.
Других решений пока нет …