Оговорка: автор вопроса имеет среднее знание Erlang и базовые знания о С.C и Erlang: пример Erlang Порт
Я читаю Interoperability Tutorial User Guide прямо сейчас. Я успешно скомпилировал пример complex.c
, и он без проблем работает с портом Erlang.
Однако, я хотел бы понять, как работает фактический код C. Я понимаю это в целом: в примере он считывает 2 байта со стандартного ввода и проверяет первый байт. В зависимости от первого байта он вызывает либо функцию foo
, либо bar
. Это предел моего понимания этого прямо сейчас.
Таким образом, если мы возьмем и erl_comm.c
:
/* 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);
}
и port.c
:
/* 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);
}
}
Что каждая функция на самом деле там делать? Какую цель выполняют li, len, i, wrote, got
переменные?
Некоторые более мелкие вопросы:
- Почему не функции имеют любые типы возврата, даже
void
ы? - Когда порт Erlang отправляет данные на C, первый байт определяет функцию для вызова. Если байт содержит десятичное число 1, то вызывается
foo()
, если байт содержит десятичное число 2, то вызываетсяbar()
. Если это не изменилось, этот протокол можно использовать для вызова до 255 различных функций C только с одним параметром. Это правильно? - «Добавление индикатора длины будет выполняться автоматически через порт Erlang, но должно выполняться явно во внешней программе C». Что это значит? На какой строке кода это делается?
- Из учебника: «По умолчанию программа C должна считывать со стандартного ввода (дескриптор файла 0) и записывать в стандартный вывод (дескриптор файла 1)». Затем: «Обратите внимание, что stdin и stdout предназначены для буферизованного ввода/вывода и не должны использоваться для связи с Erlang!» Какая уловка здесь?
- Почему
buf
инициализирован до[100]
?
Ваше предположение о 'buf' верно. Это массив, то есть смежная область памяти, способная удерживать элементы 'n' указанного типа. В этом случае память выделяется в стеке. Другой способ выделения памяти - сделать указатель 'buf' указателем и выделить его в куче, используя' malloc' (но тогда вы должны убедиться, что «освободите» память самостоятельно, когда вы закончите с ней). –
Относительно 4. Сначала в учебнике говорится, что программа C должна читать из stdin (дескриптор файла 0) и писать в stdout (дескриптор файла 1). Затем в учебнике говорится, что stdin/stdout не следует использовать для связи с Erlang ». Разве это не прямое противоречие? Они предоставляют примерную программу на языке С, которая использует stdin/stdout, а затем говорят, что ее не следует использовать, потому что stdin/stdout буферизуется. Думаю, я что-то пропустил здесь. – skanatek
@MartinLee - О. Верно, я полагаю. Я полагал, что вы не должны использовать эти порты для обратной и четвертой связи между процессами Erlang и C (это то, что для C-узла есть) .Несмотря на то, что Erlang отправляет один запрос и ожидает один ответ int на вызов программы. Возможно, я неправильно понял или неправильно понял. – Inaimathi