Более элегантный способ использовать recv () и vector <unsigned char> - PullRequest
12 голосов
/ 19 ноября 2010

Пока у меня есть пример кода:

...
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 () не выполняет распределение, согласно документации C ++ STL.И еще один вопрос: является ли использование этой техники утечкой памяти?

Ответы [ 5 ]

4 голосов
/ 19 ноября 2010

Вы мало что можете сделать, вы не можете узнать размер сообщения до 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 голосов
/ 19 ноября 2010

Этот метод является герметичным, достаточно чистым и предпочтительным.Использование std::vector является рекомендуемым способом реализации буфера переменной длины в C ++.

Если вы обнаружите, что не все данные вписываются в вектор - нет проблем, просто измените размер до большего размера и передайте адресраздел, который следует за уже заполненной частью.

Использование reserve() не очень хорошая идея - это не влияет на то, что возвращает size(), поэтому вы потеряете удобство и, вероятно, не получите никаких преимуществ.

1 голос
/ 19 ноября 2010

Я так не считаю [более элегантный способ?]. По сути, вам нужно иметь более чем достаточно символов в буфере для recv много байтов; затем, как только вы прочитаете их, если вы хотите, чтобы буфер содержал только принятые байты, вам нужно изменить размер вниз. То, что вы показали, вероятно, похоже на то, как я подхожу к вещам.

Вы правы, что reserve недостаточно. Вы не можете записывать в элементы, которые не существуют, и для них заранее выделено только хранилище.

1 голос
/ 19 ноября 2010

Этот код в порядке. Разница между resize и reserve заключается в том, что resize изменяет значение, возвращаемое size (и фактически создает новые инициализированные объекты по умолчанию), тогда как reserve нет (оно только выделяет больше памяти).

В зависимости от того, как вы обрабатываете данные, вы можете оставить второй resize и сделать это с помощью цикла, подобного следующему:

for (vector<unsigned char>::iterator it = buffer.begin(); 
     it != buffer.begin() + nbytes; 
     it++) 
{
    // process each byte
}

Таким образом, вы можете просто прочитать фактически записанные данные и игнорировать все остальное. Это означает, что вы устанавливаете размер вектора только один раз, а затем никогда не меняете его. В общем, если вы работаете только с итераторами, нет необходимости изменять размер вектора, поскольку допустимый диапазон данных всегда будет [buffer.begin(), buffer.begin() + nbytes).

0 голосов
/ 19 ноября 2010

Существует более элегантный способ использования TCP: используйте заголовок сообщения.
Вы знаете (фиксированный) размер заголовка, так что вы можете прочитать его в буфере фиксированного размера.
Внутри заголовка есть размер сообщения, так что вы можете использовать его для выделения буфера и считывания количества байтов, как указано в заголовке.

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

...