Вопрос по c, stdin, erlang-ports, erlang, stdout – C и Erlang: пример порта Erlang

8

Disclaimer: The author of the question has an average knowledge of Erlang and a basic knowledge of C.

Я читаюРуководство по взаимодействию сейчас. Я успешно скомпилировалcomplex.c пример, и он работает с портом Erlang без проблем.

Тем не менее, я хотел бы понять, как работает фактический C-код. Я понимаю это в целом: в примере он читает 2 байта из стандартного ввода и проверяет первый байт. В зависимости от первого байта он вызываетfoo или жеbar функция. Это предел моего понимания этого сейчас.

Итак, если мы возьмем обаerl_comm.c:

<code>/* erl_comm.c */

typedef unsigned char byte;

read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)
    return(-1);
  len = (buf[0] << 8) | buf[1];
  return read_exact(buf, len);
}

write_cmd(byte *buf, int len)
{
  byte li;

  li = (len >> 8) & 0xff;
  write_exact(&li, 1);

  li = len & 0xff;
  write_exact(&li, 1);

  return write_exact(buf, len);
}

read_exact(byte *buf, int len)
{
  int i, got=0;

  do {
    if ((i = read(0, buf+got, len-got)) <= 0)
      return(i);
    got += i;
  } while (got<len);

  return(len);
}

write_exact(byte *buf, int len)
{
  int i, wrote = 0;

  do {
    if ((i = write(1, buf+wrote, len-wrote)) <= 0)
      return (i);
    wrote += i;
  } while (wrote<len);

  return (len);
}
</code>

а такжеport.c:

<code>/* port.c */

typedef unsigned char byte;

int main() {
  int fn, arg, res;
  byte buf[100];

  while (read_cmd(buf) > 0) {
    fn = buf[0];
    arg = buf[1];

    if (fn == 1) {
      res = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }

    buf[0] = res;
    write_cmd(buf, 1);
  }
}
</code>

What does each function actually do there? What purpose do li, len, i, wrote, got variables actually serve?

Еще несколько небольших вопросов:

Why do not the functions have any return types, even voids? When Erlang port sends data to C, the first byte determines a function to be called. If the byte holds the decimal 1, then foo() is called, if the byte holds the decimal 2, then bar() is called. If not changed anyhow this protocol can be used to call up to 255 different C functions with only 1 parameter each. Is that right? "Adding the length indicator will be done automatically by the Erlang port, but must be done explicitly in the external C program". What does that mean? On which line of code is it done? From the Tutorial: "By default, the C program should read from standard input (file descriptor 0) and write to standard output (file descriptor 1)." Then: "Note that stdin and stdout are for buffered input/output and should not be used for the communication with Erlang!" What is the catch here? why buf is initialized to [100]?

Ваш Ответ

1   ответ
6

I just happen to be going through the same material)

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

0 - a) read_exact читаетlen байты изstdin, read_cmd использованияread_exact сначала определить, сколько байтов должно быть прочитано (либо число, обозначаемое первыми двумя байтами, либо ни одного, если доступно менее двух байтов), а затем прочитать такое количество байтов.write_exact пишетlen байты вstdout, write_cmd использованияwrite_exact вывести двухбайтовый заголовок, за которым следует сообщение (надеюсь) соответствующей длины.

0 - b) Я думаюlen достаточно покрыто выше.li это имя переменной, используемой для генерации этого двухбайтового заголовка для функции записи (я не могу шаг за шагом пройти через операции сдвига битов, но конечный результат заключается в том, чтоlen представлен в первых двух отправленных байтах).i является промежуточной переменной, основной целью которой является обеспечениеwrite а такжеread не возвращать ошибку (если они это делают, этот код ошибки возвращается в результатеread_exact/write_exact). wrote а такжеgot отслеживать, сколько байтов было записано / прочитано, содержащие циклы завершаются, прежде чем он станет больше, чемlen.

1 - Я на самом деле не уверен. Версии, с которыми я работал, имеют типint, но в остальном идентичны. Я получил свой из главы 12Программирование Erlang а не руководство, на которое вы ссылаетесь.

2 - Это правильно, но смысл протокола порта в том, что вы можете изменить его для отправки других аргументов (если вы отправляетеarbitrary аргументы, было бы лучше использовать простоC Узел метод, а не порты). В качестве примера яизменил это тонко в недавнем фрагменте, чтобы он отправлял одну строку, так как у меня есть только одна функция, которую я хочу вызвать на стороне C, устраняя необходимость в указании функции. Я должен также упомянуть, что если у вас есть система, которая должна вызывать более 255 различных операций, написанных на C, вы можете переосмыслить ее & apos; структура (или просто пойти целых девять и написать все это в C).

3 - Готово

read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)   // HERE
    return(-1);                  // HERE
  len = (buf[0] << 8) | buf[1];  // HERE
  return read_exact(buf, len);
}

вread_cmd функция и

write_cmd(byte *buf, int len)
{
  byte li;

  li = (len >> 8) & 0xff;        // HERE
  write_exact(&li, 1);           // HERE

  li = len & 0xff;               // HERE
  write_exact(&li, 1);           // HERE

  return write_exact(buf, len);
}

вwrite_cmd функция. Я думаю, что объяснение кроется в0 - a); это заголовок, который сообщает / определяет, какой длины будет оставшаяся часть сообщения (да, это означает, что оно может быть только конечной длины, и эта длина должна быть выражена в двух байтах).

4 - Я не совсем уверен, почему это было бы подвохом здесь. Хотите разработать?

5 - buf является байтовым массивом и должен быть явно ограничен (я думаю, для целей управления памятью). Я прочитал & quot;100& Quot; здесь как «число, превышающее максимальный размер сообщения, которое мы планируем разместить». Фактическое выбранное число кажется произвольным, кажется, что все, что 4 или выше, будет делать, но я мог бы быть исправлен в этом вопросе.

@MartinLee - Ой. Правда, я полагаю. Я понял, что это означает, что вы не должны использовать эти порты для обратной связи между процессами Erlang и C (это то, для чего предназначен C Node). Мы не хотя; Эрланг отправляет один запрос и ожидает одногоint ответ на вызов программы. Я думаю, что я мог неправильно понять или неправильно.
Это был мой собственный "не программист на C" понимание, так что берите с зерном соли. Это также может помочь смотретьthis, Это 5-минутный сегмент, в котором он конкретно говорит о шортах. Там также около 10 минут довольно полезных примеров на~20 minute mark.
Ваше предположение оbuf верно. Это массив, то есть непрерывная область памяти, способная содержатьn элементы указанного типа. В этом случае память распределяется по стеку. Другим способом выделения памяти было бы сделатьbuf указатель и выделить его в куче, используяmalloc (но тогда вы должны убедиться, чтоfree память, когда вы закончите с ней).
@MartinLee - Как еще мы будем рассчитыватьlen? Я полагаю, вы могли бы изменить протокол так, чтобы он использовал один байт и позволил ему буквально интерпретироваться как неподписанный байт, но это привело бы к максимальной длине сообщения 255.2длина байта скорее всего произвольная; некоторый уникальный баланс простоты хранения и длины сообщения.
Думайте с точки зрения участвующих битов.0,2 - & GT;[00000000], [00000010]. len представляет собой целое число, так что на самом деле оно составляет 4 байта;[00000000:00000000:00000000:00000000], дела[00000000] << 8 сдвигает это влево на 8 бит (в этом случае это не имеет значения, так как первый бит равен 0), давая вам[00000000:00000000], дела([00000000] << 8) | [00000010] оставляет вас с [00000000: 00000010], который является битовым представлением "короткого целого числа 2". Это назначеноlen с двумя оставшимися байтами (так что вы можете технически объявитьlen какshort integer без вредных последствий).

Похожие вопросы