Написать в файловый дескриптор и сразу прочитать из него - PullRequest
1 голос
/ 18 апреля 2020

Сегодня я столкнулся с каким-то странно выглядящим кодом, который на первый взгляд мне не совсем понятен, что он делает.

  send(file_desc,"Input \'y\' to continue.\t",0x18,0);
  read(file_desc,buffer,100);
  iVar1 = strcmp("y",(char *)buffer);
  if (iVar1 == 0) {
    // some more code
  }

Кажется, что текстовая строка записывается в дескриптор файла. Сразу же после этого он читает из этого файлового дескриптора в буфер. И он сравнивает, если текст, записанный в буфер, является "y".

Насколько я понимаю (пожалуйста, исправьте меня, если я ошибаюсь), что он записывает некоторые данные, которые являются текстовой строкой, в дескриптор файла, и затем файловый дескриптор действует как временное хранилище для всего, что вы пишете в него. И после этого он читает эти данные из файлового дескриптора в буфер. На самом деле это тот же дескриптор файла . Это выглядит как примитивный способ использования файлового дескриптора для копирования данных из текстовой строки в буфер. Почему бы просто не использовать strcpy() вместо этого?

Каков будет сценарий записи в файловый дескриптор, а затем сразу же прочитать его? Это кажется сложным способом копирования данных с использованием файловых дескрипторов. Или, может быть, я недостаточно хорошо понимаю этот код, что делает эта последовательность send() и read()?

И при условии, что этот код вместо этого использует дескриптор файла для копирования текстовой строки "Input \'y\' to continue.\t" в буфер, почему они сравнивают его со строкой "y"? Вероятно, оно должно быть ложным каждый раз.

Я предполагаю, что любые данные, записанные в файловый дескриптор, остаются в этом файловом дескрипторе до тех пор, пока не будут прочитаны. Таким образом, здесь кажется, что send() используется для записи строки, а read() используется для ее считывания.

В man send он говорит:

 The only difference between send() and write(2) is the presence of flags.  With a zero
       flags argument, send() is equivalent to write(2).

почему они используют send() вместо write()? Этот код просто ошеломляет.


Редактировать: вот полная функция, откуда этот код изначально:

void send_read(int file_desc)

{
  int are_equal;
  undefined2 buffer [8];
  char local_28 [32];

                    /* 0x6e == 110 == 'n' */
  buffer[0] = 0x6e;
  send(file_desc,"Input \'y\' to continue.\t",0x18,0);
  read(file_desc,buffer,100);
  are_equal = strcmp("y",(char *)buffer);
  if (are_equal == 0) {
    FUN_00400a86(file_desc,local_28);
  }
  else {
    close(file_desc);
  }
  return;
}

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

send(2) - системный вызов, который может использоваться только с сокетами. Сокет - это дескриптор, который позволяет использовать его для отправки данных или получения из удаленной точки (удаленного сокета), которая может находиться на другом компьютере или на том же самом месте, что и вы. Но это работает как телефонная линия: то, что вы отправляете, принимается вашим партнером, а то, что он / она отправляет, принимается вами. Системный вызов read(2) может использоваться сокетами, в то время как файлы send(2) не могут использоваться файлами, поэтому ваш пример кода смешивает вызовы, связанные с файлами, с вызовами, связанными с сокетами (это не редкость, так как read(2) и write(2) могут оба должны использоваться с сокетами)

Код, который вы публикуете выше, является ошибочным, поскольку он слепо сравнивает полученный буфер с функцией strcmp, предполагая, что он получил строку с нулевым символом в конце. Это может иметь место, но также не может.

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

  • -!, указывающее на некоторую ошибку при приеме. Соединение может быть сброшено с другой стороны, или другая сторона могла перезагрузиться, пока вы отправляете данные.
  • 0, указывающий больше нет данных или конец данных (другая сторона закрыла соединение) Это может произойти, если у другой стороны есть тайм-аут, и вы берете слишком много, чтобы ответить. Он закрывает соединение, ничего не отправляя. Вы просто ничего не получаете.
  • n некоторые данные, меньше буфера размер, но включая полный пакет, отправленный узлом (и согласованный нулевой байт, который он отправил вместе с ним). Это единственный случай, когда вы можете безопасно strcmp данные.
  • n некоторые данные, меньше, чем размер буфера, и меньше, чем переданные данные. Это может произойти из-за некоторой фрагментации данных данных в нескольких пакетах. Затем вам придется делать еще один read, пока вы не получите все данные, отправленные вашим пэром. Например, фрагментация пакетов является чем-то естественным в TCP.
  • n некоторые данные, меньше размера буфера и больше передаваемых данных. Отправитель сделал еще одну передачу, после того, как вы получили, и оба пакета попали в буфер ядра. Вы должны исследовать этот случай, поскольку у вас есть один полный пакет, и вы должны сохранить оставшиеся полученные данные в буфере для последующей обработки, иначе вы потеряете полученные данные.
  • n некоторые данные, полный буфер заполнен, и не осталось места для хранения всех переданных данных. Вы заполнили буфер, и \0 char не пришло ... пакет больше, чем буфер, вам не хватает места в буфере, и вам нужно решить, что делать (выделить другой буфер для получения остатка, отбросить данные или все, что вы решите сделать) Это не произойдет с вами, потому что вы ожидаете пакет из 1 или 2 символов, и у вас есть буфер 100, но кто знает ...

По крайней мере, и как минимальный сейф net, вы можете сделать это:

  send(file_desc,"Input \'y\' to continue.\t",0x18,0);
  int n = read(file_desc,buffer,sizeof buffer - 1);  /* one cell reserved for '\0' */
  switch (n) {
  case -1: /* error */
      do_error();
      break;
  case 0: /* disconnect */
      do_disconnect();
      break;
  default: /* some data */
      buffer[n] = '\0';  /* append the null */
      break;
  }
  if (n > 0) {
      iVar1 = strcmp("y",(char *)buffer);
      if (iVar1 == 0) {
        // some more code
      }
  }

Примечание:

Поскольку вы не опубликовали полный и проверяемый пример, я не смог опубликовать полный и проверяемый ответ.

Мои извинения за это.

1 голос
/ 18 апреля 2020

Функции send() и recv() предназначены для использования с сокетами (send: отправить сообщение в сокет - recv: получить сообщение из подключенного сокета ). См. Также описание POSIX Сокетов в целом.

Дескрипторы файлов сокетов являются двунаправленными - вы можете читать и писать на них. Вы не можете прочитать то, что написали, в отличие от дескрипторов файлов канала. С помощью каналов процесс, записывающий запись в конец канала, может прочитать то, что он написал, из конца чтения канала - если другой процесс не прочитал его первым. Когда процесс записывает данные в сокет, эта информация передается равноправному процессу и не может быть прочитана записывающим устройством.

...