C和Erlang:Erlang Port示例 [英] C and Erlang: Erlang Port example

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

问题描述

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



我正在阅读< a href =http://www.erlang.org/doc/tutorial/users_guide.html =noreferrer>互操作性教程用户指南。我已经成功编译了 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);
得到+ = i;
} while(获得
return(len);
}

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

do {
if((i = write(1,buf + written,len-written))< = 0)
return(i);
写了+ = i;
} while(written< 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);
}
}

每个功能实际上在做什么?


  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 中读取前两个字节,假设它表示实际消息的长度,然后从标准输入。在这种具体情况下,实际的消息始终是两个字节(一个对应于一个函数的数字和一个整数参数传递给它)。



0 - a) read_exact stdin len c $ c>, read_cmd 首先使用 read_exact 来确定应该读取多少字节(由前两个字节,如果有少于两个字节可用,则为none),然后读取该字节数。 write_exact len 个字节写入 stdout write_cmd 使用 write_exact 输出一个两字节长度的标题,然后是一个消息(希望的)适当的长度。



0 - b)我认为 len 上面已经充分说明了。 li 是用于为写入函数生成两个字节头的变量的名称(我不能一步一步地通过位移操作,但是最终结果是发送的前两个字节表示 len i 是一个中间变量,其主要目的似乎是确保写入读取不返回一个错误(如果他们这样做,该错误代码作为 read_exact / write_exact )。记住和获得跟踪已经写入/读取了多少字节,包含循环在它变得大于之前退出 len



1 - 我其实不确定。我正在使用的版本是类型 int ,但其他方式相同。我从编程Erlang第12章中得到了解,而不是您链接的指南。 p>

2 - 这是正确的,但端口协议的要点是您可以将其更改为发送不同的参数(如果您正在发送任意的参数,使用 C Node可能会更好一个主意方法而不是端口)。例如,我修改它巧妙地在一个最近的一个,因为它发送一个单一的字符串,因为我只有一个功能,我想在C方面调用,不需要指定一个功能。我还应该提到,如果你有一个需要调用超过255种不同操作的系统,你可能想重新考虑它的结构(或者只是整个九,并且全部写在C中)。



3 - 这是完成

  read_cmd * 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或更高的值都可以,但是我可以在这一点上得到纠正。


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和Erlang:Erlang Port示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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