Нужно ли смещать указатель при вызове recv?

#c #c #pointers #networking #recv

Вопрос:

При использовании recv я всегда делал что-то подобное:

 int len = 1000; int n = 0;  char buf[1000]; while(n lt; len) {  n  = recv(socket, buf   n, len - n, 0); }   

моя логика заключается в том, что если recv не получает полные данные len байтов, я должен получать только остальные байты ( len - n ) и не должен перезаписывать уже полученные данные (поэтому я смещаю начало буфера до конца уже полученного содержимого). Кажется, это прекрасно работает всякий раз, когда я его использую.

Однако большинство, если не все примеры recv, которые я вижу, просто делают что-то вроде следующего:

 int len = 1000; int n = 0;  char buf[1000]; while(n lt; len) {  n  = recv(socket, buf, len, 0); }   

Не делает ли это вас уязвимым для перезаписи начала вашего буфера, если recv вызывается более одного раза?

Комментарии:

1. » большинство, если не все примеры recv «. Если эти примеры не просто пытаются использовать данные без их использования или вы не вырвали их из контекста, то это выглядит неправильно, как вы заявили.

2. Ваше «смещение» возникает из-за того, что вы пытаетесь сохранить данные из нескольких вызовов recv() в массив, т. Е. вы не всегда считываете первый элемент массива. Примеры, на которые вы ссылаетесь, все считываются с первого символа буфера (поэтому данные о втором и последующих вызовах recv() перезаписывают ранее полученные элементы массива). Оба подхода верны, но в разных обстоятельствах (т. Е. Не существует какого-то волшебного рецепта «всегда делай это»). Во всех случаях необходимо убедиться, что ваш код не проходит дальше конца массива.

Ответ №1:

Оба ваших примера не учитывают возможность recv() неудачи. Вам нужно проверить возвращаемое значение на наличие ошибок, например:

 char buf[1000]; int len = sizeof(buf); int n = 0, ret;  while (n lt; len) {  ret = recv(socket, buf   n, len - n, 0);  if (ret lt;= 0) {  // error handling...  break;  }  n  = ret; }  

Ваш 1-й пример хорошо использовать, когда вы заранее точно знаете, сколько байтов вам нужно прочитать, и можете предварительно выделить буфер, достаточно большой, чтобы вместить все это.

Ваш 2-й пример хорошо использовать, когда вам нужно передавать данные более динамично, по 1 буферу за раз. Например, возможно, данные сохраняются в файл. Или, может быть, данные слишком велики, чтобы поместиться в такой маленький буфер, и их необходимо обрабатывать по частям. Или, может быть, данные добавляются в другой динамически растущий буфер для последующего использования. Множество причин для этого варианта использования, например:

 char buf[1000]; int n;  while (some condition) {  n = recv(socket, buf, sizeof(buf), 0);  if (n lt;= 0) {  // error handling...  break;  }  // use buf up to n bytes... }  

Ответ №2:

все это плохо. если мы говорим о C, вам нужно, по крайней мере, место для . вы можете удалить его только тогда, когда будете уверены, что все в порядке. иначе вы не смогли бы это проверить. И все это означает, что вы не уверены, что сможете сделать все это одним ударом, так что, возможно, у вас есть право голоса Transfer-Encoding: chunked . Если вы этого не сделаете

 int btx; .... char x[9001] = {0}; int b = 0; int e = 0; do {  b = recv(btx, x   e, 9000, 0);  e = e   b; }while(b != 0);  

И C

 std::stringstream fbtc_b; int btx; .... int b = 0; do {  char x[9000];  b = recv(btx, x, 9000, 0);  fbtc_b.write(x, b); }while(b != 0);