Два раза отправить и получить не работает C

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

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

Вот часть, куда я отправляю:

char to_send[] = "hello. I am the Data.";

  // get size of data
  int len = strlen(to_send);
  char slen[len];
  sprintf(slen,"%d",len);
  printf("%s\n",slen);
  // send size of data
  if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}

  // send data
  if(send(comm_fd,to_send,len,0)<0){perror("Error on send"); exit(1);}

И вот часть, где я получаю:

// getting size of bytes to recv
  char buf[1000];
  bzero(buf,1000);

  int rec = recv(comm_fd, buf, 100,0);
  printf("rec\n: %i",rec);
  printf("buf\n: %s\n", buf);

  int buffsize;
  buffsize = atoi(buf);
  bzero(buf,1000);
  printf("buffsize: %i\n",buffsize);

  // recv the bytes
  bzero(buf,1000);
  rec = recv(comm_fd, buf, buffsize,0);
  printf("rec\n: %i",rec);
  printf("%s",buf);

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

Кто-нибудь может мне помочь? Я думаю, что делаю что-то неправильно (я новичок в C и в сетевом программировании)

заранее спасибо


person Minory    schedule 02.09.2016    source источник
comment
Размер slen не len   -  person Fozi    schedule 02.09.2016


Ответы (1)


Две вещи с этим первым вызовом send:

if(send(comm_fd,slen,len,0)<0){perror("Error on send"); exit(1);}

Здесь вы отправляете len количество байтов, но len — это длина to_send, а не длина slen. Скорее всего, вы отправите данные из-за пределов инициализированных частей slen, что приведет к неопределенному поведению.

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

Обе эти проблемы можно решить, сделав slen массивом фиксированного размера, достаточно большим, чтобы вместить самые большие числа, которые вы можете придумать (обычно достаточно десяти цифр), а затем отправить этот массив фиксированной длины с помощью sizeof slen .

Возможно что-то вроде этого:

// Ten digits, plus string terminator
char slen[10 + 1];

// Prefix length with zeroes, and don't overflow the buffer
snprintf(slen, sizeof(slen), "%010d", strlen(to_send));

// Send the whole array, including terminator
send(comm_fd, slen, sizeof slen, 0);

Затем на принимающей стороне вы можете сделать

// Ten digits, plus string terminator
char slen[10 + 1];

// Receive the whole string, including terminator
recv(comm_fd, slen, sizeof(slen), 0);

// Convert to a number
size_t len = strtoul(slen, NULL, 10);

// Now receive `len` bytes

Обратите внимание, что у меня нет проверки ошибок, которая должна быть у вас.

person Some programmer dude    schedule 02.09.2016
comment
это сработало! большое спасибо! Я вижу свои ошибки, объявление будет читать о функциях, которые вы использовали. Благодарность - person Minory; 02.09.2016
comment
Кроме того, в современных программах используйте memset вместо bzero (что устарело в POSIX). - person David Ranieri; 02.09.2016
comment
snprintf(slen, sizeof(slen), "%010d", strlen(to_send)); имеет проблемы. Типичный int (который является типом, ожидаемым с %d) требует до 11 + 1 char, а не 10. например. -2147483648. strlen() возвращает тип size_t, который может не совпадать с %d. Возможно, вы хотите %zu, тогда 10 может быть в порядке. Код, который использует snprintf() для предотвращения переполнения и не проверяет возвращаемое значение snprintf(), подменяет одну проблему другой. Лучше проверить его возвращаемое значение. - person chux - Reinstate Monica; 02.09.2016
comment
size_t len = strtoul(slen, NULL, 10); выиграет от предыдущего slen[sizeof slen -1] = 0;. Рекомендуйте это защитное кодирование, так как нельзя полностью доверять входным данным другого процесса. - person chux - Reinstate Monica; 02.09.2016