C和二郎:二郎口为例 [英] C and Erlang: Erlang Port example

查看:178
本文介绍了C和二郎:二郎口为例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我读了互操作性指南用户指南现在。我已经成功编制了 complex.c里的例子,它与二郎神港口工作没有任何问题。

不过,我想了解实际的C code工作。我的理解一般:在本例中读取从标准输入2个字节,检查第一个字节。根据第一个字节它要求无论是功能。这是我对它的理解极限现在。

所以,如果我们把两个 erl_comm.c

  / * * erl_comm.c /的typedef unsigned char型字节;read_cmd(BYTE * BUF)
{
  INT LEN;  如果(read_exact(BUF,2)!= 2)
    返回(-1);
  LEN =(BUF [0]&下;&下; 8)| BUF [1];
  返回read_exact(BUF,LEN);
}WRITE_CMD(BYTE * BUF,INT LEN)
{
  李字节;  利=(LEN>→8)及0xFF的;
  write_exact(安培;李,1);  李= LEN&安培; 0xFF的;
  write_exact(安培;李,1);  返回write_exact(BUF,LEN);
}read_exact(BYTE * BUF,INT LEN)
{
  INT I,得到= 0;  做{
    如果((ⅰ=读(0,BUF +得到,LEN-得到))≤; = 0)
      返回(ⅰ);
    有+ =我;
  }而(有< LEN);  返程(LEN);
}write_exact(BYTE * BUF,INT LEN)
{
  INT I,写= 0;  做{
    如果((I =写(1 + BUF写道:LEN-写))< = 0)
      返回(ⅰ);
    写+ =我;
  }而(写< LEN);  返程(LEN);
}

port.c

  / * * port.c /的typedef unsigned char型字节;诠释主(){
  INT FN,阿根廷,资源;
  字节的buf [100];  而(read_cmd(BUF)大于0){
    FN = BUF [0];
    精氨酸= BUF [1];    如果(FN == 1){
      RES =富(阿根廷);
    }否则如果(FN == 2){
      RES =栏(ARG);
    }    BUF [0] =资源;
    WRITE_CMD(BUF,1);
  }
}

什么是每个函数实际上做呢?目的是什么做的里,LEN,我写道,拿到变量实际上服务?

更多的一些小问题:


  1. 为什么不函数有任何返回类型,即使无效 S'

  2. 当二郎端口发送数据至C,所述第一字节确定一个被调用的功能。如果字节保持小数1,则富()叫,如果字节保持小数2,那么巴()被调用。如果没有改变,无论如何这个协议可以用来与各只有1个参数调用255不同的C函数。是这样吗?

  3. 添加长度指示将自动被二郎神​​端口来完成,但必须在外部C程序做了明确的。这意味着什么?上code的线是它做?

  4. 从教程:
    默认情况下,C程序应该从标准输入(文件描述符0)读取和写入到标准输出(文件描述符1)。
    然后:注意stdin和stdout是用于缓冲输入/输出,而不应被用于使用Erlang通信!什么是抓吗?

  5. 为什么 BUF 初始化为 [100]


解决方案

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

您最初的模式是有点过。在code实际工作的方式是从标准输入看完前两个字节,假定它意味着实际消息的长度,然后读取从更多的字节标准输入。在这种特定的情况下,它发生实际的消息通常是两个字节(对应于一个功能和一个整数参数一批要传递给它)。

0 - A) read_exact LEN 从字节标准输入 read_cmd 使用 read_exact 首先要确定它应该有多少字节读取(无论是由前两个字节标志着一个数,或无是否有可用少于两个字节),然后读取多个字节。 write_exact 写入 LEN 字节来标准输出 WRITE_CMD 使用 write_exact 来输出两个字节长度的头,其次是适当长度的消息(希望)。

0 - B)我觉得 LEN 充分以上覆盖。 是用于生成两个字节的报头写功能(我不能带你穿越位移位运算步步变量的名称,但最终的结果是 LEN 重新发送中的前两个字节)psented $ p $。 I 是一个中间变量,其主要目的似乎是确保不返回错误(如果他们这样做,是错误code返回为 read_exact / write_exact )。 获得跟踪多少字节被写入/读取,含环退出才变得大于 LEN

1 - 实际上,我不知道。我一起工作的版本类型 INT 的,但完全一样。我得到了我出编程二郎而不是你链接导向的第12章。

2 - 这是正确的,但端口协议的一点是,你可以改变它发送不同的参数(如果你发送的任意的参数,它会可能是一个更好的主意,只是使用 C节点的方法,而不是端口)。举个例子,我修改了它巧妙地的在最近的一块使它发送一个字符串,因为我只有一个功能,我想在C端调用,省去了指定功能的需要。我还要提到的是,如果你有需要调用255个以上的C语言编写的不同操作的系统,你可能要重新考虑其结构(或者只是去整个九,这一切写在C)。

3 - 这样做是

  read_cmd(BYTE * BUF)
{
  INT LEN;  如果(read_exact(BUF,2)!= 2)//这里
    返回(-1); // 这里
  LEN =(BUF [0]&下;&下; 8)| BUF [1]; // 这里
  返回read_exact(BUF,LEN);
}

read_cmd 功能以及

  WRITE_CMD(BYTE * BUF,INT LEN)
{
  李字节;  利=(LEN>→8)及0xFF的; // 这里
  write_exact(安培;李,1); // 这里  李= LEN&安培; 0xFF的; // 这里
  write_exact(安培;李,1); // 这里  返回write_exact(BUF,LEN);
}

WRITE_CMD 功能。我想说明在 0覆盖 - A);这是一个头,告诉/发现该消息的其余部分多久会(是的,这意味着它只能是有限的长度,而且长度必须在两个字节前pressible)。

4 - 我不完全知道为什么,这将是一个catch这里。详细地谈一谈?

5 - BUF 是一个字节数组,并有明确界定(内存管理的目的,我认为)。我读 100 在这里作为一些比我们计划以适应最大邮件大小。采摘的实际数量似乎武断,这似乎像什么4或更高版本会做,但我可以站在这一点上加以纠正。

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

I am reading the Interoperability Tutorial User Guide now. I have successfully compiled the complex.c example and it works with the Erlang Port without any problems.

However, I would like to understand how the actual C code works. I understand it in general: in the example it reads 2 bytes from the standard input and checks the first byte. Depending on the first byte it calls either foo or bar function. This is the limit of my understanding of it right now.

So, if we take both 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);
}

and 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);
  }
}

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

Some more small questions:

  1. Why do not the functions have any return types, even voids?
  2. 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?
  3. "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?
  4. 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?
  5. why buf is initialized to [100]?

解决方案

This answer is likewise disclaimed (I'm not an Erlang or C programmer, I just happen to be going through the same material)

Your initial model is a bit off. The way the code actually works is by reading the first two bytes from stdin, assuming that it signifies the length of the actual message, then reading that many more bytes from stdin. In this specific case, it happens that the actual message is always two bytes (a number corresponding to a function and a single integer argument to pass to it).

0 - a) read_exact reads len bytes from stdin, read_cmd uses read_exact first to determine how many bytes it should read (either a number signified by the first two bytes, or none if there are fewer than two bytes available), and then to read that many bytes. write_exact writes len bytes to stdout, write_cmd uses write_exact to output a two byte length header, followed by a message (hopefully) of the appropriate length.

0 - b) I think len is sufficiently covered above. li is the name of the variable used to generate that two-byte header for the write function (I can't take you through the bit shift operations step by step, but the end result is that len is represented in the first two bytes sent). i is an intermediate variable whose main purpose seems to be making sure that write and read don't return an error (if they do, that error code is returned as the result of read_exact/write_exact). wrote and got keep track of how many bytes have been written/read, the containing loops exit before it becomes greater than len.

1 - I'm actually not sure. The versions I was working with are of type int, but otherwise identical. I got mine out of chapter 12 of Programming Erlang rather than the guide you link.

2 - That's correct, but the point of the port protocol is that you can change it to send different arguments (if you're sending arbitrary arguments, it would probably be a better idea to just use the C Node method rather than ports). As an example, I modified it subtly in a recent piece so that it sends a single string, since I only have one function I want to call on the C side, eliminating the need for specifying a function. I should also mention that if you have a system which needs to call more than 255 different operations written in C, you may want to rethink its' structure (or just go the whole nine and write it all in C).

3 - This is done

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);
}

in the read_cmd function and

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);
}

in the write_cmd function. I think the explanation is covered in 0 - a); that's a header that tells/finds out how long the rest of the message will be (yes, this means that it can only be a finite length, and that length must be expressible in two bytes).

4 - I'm not entirely sure why that would be a catch here. Care to elaborate?

5 - buf is a byte array, and has to be explicitly bounded (for memory management purposes, I think). I read "100" here as "a number larger than the maximum message size we plan to accommodate". The actual number picked seems arbitrary, it seems like anything 4 or higher would do, but I could stand to be corrected on that point.

这篇关于C和二郎:二郎口为例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆