C和Erlang的:二郎港口例如(C and Erlang: Erlang Port example

2019-07-29 07:11发布

免责声明:这个问题的作者有二郎的平均知识和C语言的基础知识

我读的互操作性教程使用手册吧。 我已经成功编译complex.c例子,并与二郎神端口工作没有任何问题。

不过,我想了解实际的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) | 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 ,变量实际上服务?

一些更小的问题:

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

Answer 1:

这个答案同样否认(我不是一个Erlang或C程序员,我只是碰巧通过相同的材料去)

您最初的模式是有点过。 代码实际的工作方式是通过从读出的前两个字节stdin ,假定它表示实际的消息的长度,然后读取来自许多更多的字节stdin 。 在这种特定情况下,它发生实际的消息通常是两个字节(对应于功能和一个整数参数的数传递给它)。

0 -一) read_exact读取len从字节stdinread_cmd使用read_exact第一,以确定它应当多少字节读(或由前两个字节所指的数,或没有,如果有少于两个字节提供),然后读很多字节。 write_exact写入len字节到stdoutwrite_cmd使用write_exact以输出两个字节长度头,后跟适当的长度的消息(希望)。

0 - b)中 ,我认为len被充分上方覆盖。 li是用来产生用于写功能(我不能把你通过位移运算一步一步的是两个字节的报头中的变量的名称,但最终的结果是, len在发送的前两个字节表示的)。 i是一个中间变量,其主要目的似乎是确保使writeread不返回一个错误(如果他们这样做,是错误代码返回的结果read_exact / write_exact )。 wrotegot跟踪多少字节已经写入/读取,含循环退出之前它变得大于len

1 -实际上,我不知道。 我正在同该版本类型int ,但完全一样。 我有我出的第12章的编程Erlang的 ,而不是你链接的指南。

2 -这是正确的,但端口协议的一点是,你可以改变它发送不同的参数(如果你发送任意参数,它很可能是一个更好的主意,只需使用Ç节点的方法,而不是端口)。 作为一个例子,我改性它巧妙地在最近的一块,使得它发送一个字符串,因为我只有一个功能我想在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 -我不完全知道为什么,这将是一个catch这里。 详细地谈一谈?

5 - buf是一个字节数组,并且必须被明确限定(用于存储器管理的目的,我想)。 我读了“ 100 ”这里“一些比我们计划,以满足最大邮件大小”。 采摘的实际数量似乎随意,好像什么4或更高版本会做,但我可以站在该点的修正。



文章来源: C and Erlang: Erlang Port example