C和Erlang:Erlang Port示例

免责声明:该问题的作者具有Erlang的平均知识和C的基本知识。

我现在正在阅读互操作性教程用户指南 。 我已成功编译了complex.c示例,它与Erlang端口一起使用没有任何问题。

但是,我想了解实际的C代码是如何工作的。 我一般都理解它:在示例中,它从标准输入读取2个字节并检查第一个字节。 根据第一个字节,它调用foobar函数。 这是我现在对它的理解的极限。

所以,如果我们同时使用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) & 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); } } 

每个function实际上做了什么? li, len, i, wrote, got变量实际服务的目的是什么?

一些小问题:

  1. 为什么函数没有任何返回类型,甚至是void s?
  2. 当Erlang端口向C发送数据时,第一个字节确定要调用的函数。 如果该字节保存小数1,则调用foo() ,如果该字节包含小数2,则调用bar() 。 如果不改变,无论如何这个协议可用于调用多达255个不同的C函数,每个函数只有1个参数。 是对的吗?
  3. “添加长度指示符将由Erlang端口自动完成,但必须在外部C程序中明确完成”。 那是什么意思? 在哪一行代码完成?
  4. 从教程:“默认情况下,C程序应从标准输入(文件描述符0)读取并写入标准输出(文件描述符1)。” 然后:“注意stdin和stdout用于缓冲输入/输出,不应该用于与Erlang的通信!” 这里有什么收获?
  5. 为什么buf被初始化为[100]

同样放弃了这个答案(我不是Erlang或C程序员,我恰好经历了相同的材料)

你的初始模型有点偏。 代码实际工作的方式是从stdin读取前两个字节,假设它表示实际消息的长度,然后从stdin读取更多的字节。 在这种特定情况下,实际消息总是两个字节(一个对应于一个函数的数字和一个传递给它的单个整数参数)。

0 – a) read_exactstdin读取len个字节, read_cmd使用read_exact来确定它应该读取多少字节(前两个字节表示的数字,如果可用的字节少于两个,则为none),然后读取那很多字节。 write_exactlen字节写入stdoutwrite_cmd使用write_exact输出一个两字节长度的头,然后是一个适当长度的消息(希望如此)。

0 – b)我认为len已在上面充分涵盖。 li是用于为写入函数生成该双字节头的变量的名称(我不能逐步引导您进行位移操作,但最终结果是len在发送的前两个字节中表示)。 i是一个中间变量,其主要目的似乎是确保writeread不会返回错误(如果这样做,则会返回错误代码作为read_exact / write_exact的结果)。 wrote并记录已写入/读取的字节数,包含循环在大于len之前退出。

1 –我其实不确定。 我使用的版本是int类型,但在其他方面相同。 我从编程Erlang的第12章开始,而不是你链接的指南。

2 –这是正确的,但是端口协议的要点是你可以改变它来发送不同的参数(如果你发送任意参数,那么使用C Node方法而不是端口可能是更好的主意)。 作为一个例子,我在最近的一篇文章中巧妙地修改它 ,以便它发送一个字符串,因为我只有一个我想在C端调用的函数,因此无需指定函数。 我还要提一下,如果你的系统需要调用超过255个用C语言编写的不同操作,你可能想重新考虑它的结构(或者只是整个九个并用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是一个字节数组,必须明确限制(出于内存管理的目的,我认为)。 我在这里读“ 100 ”是“比我们计划容纳的最大消息大小更大的数字”。 选择的实际数字似乎是任意的,似乎任何4或更高的数字都可以,但我可以在这一点上得到纠正。