Подтвердить что ты не робот

Более элегантный способ использования 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. И еще один вопрос: использует ли этот метод безопасность утечки памяти?

4b9b3361

Ответ 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: использование заголовка сообщения.
Вы знаете (фиксированный) размер заголовка, поэтому вы можете прочитать это в буфере фиксированного размера.
Внутри заголовка есть размер сообщения, поэтому вы можете использовать его для выделения своего буфера и чтения количества байтов, как указано в заголовке.

Помните, что с помощью этого вам могут понадобиться некоторые методы для секционных случаев, таких как фрагментация для длинных сообщений.