Более элегантный способ использования recv() и vector <unsigned char>
Пока у меня есть этот пример кода:
...
int nbytes =0;
vector<unsigned char> buffer;
buffer.resize(5000);
nbytes = recv(socket, &buffer[0], buffer.size(),0);
//since I want to use buffer.size() to know data length in buffer I do
...
buffer.resize(nbytes);
Это другой способ, чтобы знать длину данных в буфере без использования resize() дважды? Потому что невозможно получить данные в вектор, который не изменяется до нужного размера. Я думаю, что метод reserve() не выполняет выделение, согласно документации С++ STL. И еще один вопрос: использует ли этот метод безопасность утечки памяти?
Ответы
Ответ 1
Этот метод является безопасным для утечки, достаточно чистым и предпочтительным. Использование std::vector
- рекомендуемый способ реализации буфера переменной длины в С++.
Если вы обнаружите, что не все данные вписываются в вектор - без проблем, просто измените размер до большего размера и передайте адрес раздела, который следует за уже заполненной частью.
Использование reserve()
- не очень хорошая идея - это не влияет на то, что возвращает size()
, поэтому вы потеряете удобство и, вероятно, не получите никаких преимуществ.
Ответ 2
Вы не можете многое сделать, вы не можете знать размер сообщения перед вызовом recv
.
Некоторая очистка:
std::vector<unsigned char> buffer(5000);
int result = recv(socket, buffer.data(), buffer.size(), 0);
if (result != -1) {
buffer.resize(result);
} else {
// Handle error
}
Ответ 3
Этот код в порядке. Разница между resize
и reserve
заключается в том, что resize
изменяет значение, возвращаемое size
(и фактически создает новые инициализированные объекты по умолчанию), тогда как reserve
не (выделяет больше памяти).
В зависимости от того, как вы обрабатываете данные, вы можете оставить второй resize
out и сделать это с помощью цикла следующим образом:
for (vector<unsigned char>::iterator it = buffer.begin();
it != buffer.begin() + nbytes;
it++)
{
// process each byte
}
Таким образом, вы можете просто прочитать данные, которые были написаны на самом деле, и игнорировать остальные. Это означает, что вы только установили размер вектора один раз, а затем никогда не измените его. В общем, пока вы работаете только с итераторами, нет необходимости изменять размер вектора, так как допустимый диапазон данных всегда будет [buffer.begin(), buffer.begin() + nbytes)
.
Ответ 4
Я не верю, что это [более элегантный способ?]. По сути, вам нужно иметь более чем достаточно символов в буфере до recv
много байтов; то, как только вы их прочтете, если вы хотите, чтобы в буфере содержались только полученные байты, вам нужно изменить размер вниз. То, что вы показали, вероятно, похоже на то, как я буду приближаться к вещам.
Вы правы, что reserve
недостаточно. Вы не можете писать элементы, которые не существуют, и у них было только хранилище, выделенное для них заранее.
Ответ 5
Существует более элегантный способ использования TCP: использование заголовка сообщения.
Вы знаете (фиксированный) размер заголовка, поэтому вы можете прочитать это в буфере фиксированного размера.
Внутри заголовка есть размер сообщения, поэтому вы можете использовать его для выделения своего буфера и чтения количества байтов, как указано в заголовке.
Помните, что с помощью этого вам могут понадобиться некоторые методы для секционных случаев, таких как фрагментация для длинных сообщений.