Я использую библиотеку сокетов (я бы не стал ее использовать), чьи операции recv
работают с std::string
, но являются просто оберткой для одного вызова функции сокета recv
, так что, вероятно, что я получил только часть сообщения, которое хотел. Моим первым инстинктом было зацикливание и добавление полученной строки к другой строке, пока я не получу все, но это кажется неэффективным. Другой возможностью было сделать то же самое с массивом символов, но это кажется грязным. (Мне нужно проверить размер строк перед добавлением в массив, и если он переполнится, мне нужно где-то хранить строку, пока массив снова не станет пустым ..)
Так что я думал об использовании струнного потока. Я использую протокол TLV, поэтому мне нужно сначала извлечь два байта в unsigned short, затем получить определенное количество байтов из потока строк и затем повторять цикл, пока я не достигну поля разделителя.
Есть ли лучший способ сделать это? Я совершенно не на том пути? Есть ли лучшие практики? До сих пор я всегда видел только прямое использование библиотеки сокетов с массивами символов, поэтому мне любопытно, почему использование `std :: string`` со строковыми потоками может быть плохой идеей ..
Редактировать: Ответ на комментарий ниже: Библиотека - это библиотека, которую мы используем внутри, она не является публичной (хотя в ней нет ничего особенного, в основном это просто оболочка для библиотеки сокетов для добавления исключений и т. Д.).
Я должен упомянуть, что у меня есть рабочий прототип, использующий библиотеку сокетов напрямую.
Это работает примерно так:
int lengthFieldSize = sizeof(unsigned short);
int endOfBuffer= 0;//Pointer to last valid position in buffer.
while(true) {
char buffer[RCVBUFSIZE];
while(true) {
int offset= endOfBuffer;
int rs= 0;
rs= recv(sock, buffer+offset, sizeof(buffer)-offset, 0);
endOfBuffer+= rs;
if(rs < 1) {
// Received nothing or error.
break;
} else if(endOfBuffer == RCVBUFSIZE) {
// Buffer full.
break;
} else if(rs > 0 && endOfBuffer > 1) {
unsigned short msglength= 0;
memcpy((char *) &msglength, buffer+endOfBuffer-lengthFieldSize, lengthFieldSize);
if(msglength == 0) {
break; // Received a full transmission.
}
}
}
unsigned int startOfData = 0;
unsigned short protosize= 0;
while(true) {
// Copy first two bytes into protosize (length field)
memcpy((char *) &protosize, buffer+startOfData, lengthFieldSize);
// Is the last length field the delimiter?
// Then reply and return. (We're done.)
// Otherwise: Is the next message not completely in the buffer?
// Then break. (Outer while will take us back to receiving)
if(protosize == 0) {
// Done receiving. Now send:
SendReplyMsg(sock, lengthFieldSize);
// Clean up.
close(sock);
return;
} else if((endOfBuffer-lengthFieldSize-startOfData) < protosize) {
memmove(buffer, buffer+startOfData, RCVBUFSIZE-startOfData);
//Adjust endOfBuffer:
endOfBuffer-=startOfData;
break;
}
startOfData+= lengthFieldSize;
gtControl::gtMsg gtMessage;
if(!gtMessage.ParseFromArray(buffer+startOfData, protosize)) {
cerr << "Failed to parse gtMessage." << endl;
close(sock);
return;
}
// Move position pointer forward by one message (length+pbuf)
startOfData+= protosize;
PrintGtMessage(>Message);
}
}
Так что в основном у меня есть большой цикл, который содержит цикл приема и цикл синтаксического анализа. Массив символов передается туда-сюда, так как я не могу быть уверен, что получил все, пока не проанализирую его. Я пытаюсь воспроизвести это поведение, используя «правильный» C ++ (т.е. std :: string)