Erlang调用C程序

本文是《Erlang程序设计》中的示例,因为C语言基础薄弱,理解这节花了一些时间,示例中的C程序分为三个文件,为了便于调试,我合并成了一个文”c.c”,而Erlang代码则叫”e.erl”,在代码中加入了一些便于理解的注释。

主要用到的Erlang函数为:open_port(PortName,[Opt])

参数其中PortName可以是下列选项中的一个:

{spawn,Command}

启动一个外部程序。Command是这个外部程序的名称。

{fd,In,Out}

允许一个Erlang进程访问Erlang使用的任何当前打开文件描述符。文件描述符In可以用作标准输入,文件描述符Out会在

Erlang工作空间之外运行。

参数Opt可以是下列选项中的一个:

{packet,N}

数据包(packet)前面有N(1/2/4)个字节长度计数(包头)。

stream

e.erl

-module(e).
-export([start/0,stop/0,twice/1,sum/2,call_port/1,loop/1]).

start() ->
    register(e,spawn(fun() ->
            process_flag(trap_exit,true),
            %% 启动一个名为c的外部可执行程序,{packet,2}表示根据包大小自动添加2字节的包头
            Port = open_port({spawn,"./c"},[{packet,2}]),
            loop(Port)
         end)).

stop() ->
    ?MODULE ! stop.

sum(X,Y) ->
    call_port({sum,X,Y}).

twice(X) ->
    call_port({twice,X}).

call_port(Msg) ->
    ?MODULE ! {call,self(),Msg},
    receive
        {?MODULE,Result} ->
            Result
    end.

loop(Port) ->
    receive
        {call,Caller,Msg} ->
            %% 发送示例 :调用 e:sum(3,4),encode后向端口发送 {self(),{command,[1,3,4]}} 的消息内容,
            %% 端口驱动自动给消息内容加上两个字节的长度包头{0,3},表示消息内容有3个字节,然后把 {0,3,1,3,4} 发送给外部C程序
            Port ! {self(),{command,encode(Msg)}},
            receive
                %% 接收示例:返回{0,1,7},端口驱动移除长度包头{0,1},然后向相连进程发送一个{Port,{data,[7]}}的消息
                {Port,{data,Data}} ->
                    Caller ! {?MODULE,decode(Data)}
            end,
            loop(Port);

        stop ->
            Port ! {self(),close},
            receive
                {Port,closed} ->
                    exit(normal)
            end;
        {‘EXIT‘,Port,Reason} ->
            exit({port_terminated,Reason})
    end.

encode({sum,X,Y}) ->
    [1,X,Y];

encode({twice,X}) ->
    [2,X].

decode([Int]) ->
    Int.

c.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

typedef unsigned char byte;

int read_cmd(byte *buff);
int read_exact(byte *buf,int len);
int write_cmd(byte *buff,int len);
int write_exact(byte *buf,int len);
int sum(int x,int y);
int twice(int x);

int main() {
    int fn,arg1,arg2,result;
    byte buff[100];
    while( read_cmd(buff) >0 ) {
        fn = buff[0];
        if( fn == 1) {
            arg1 = buff[1];
            arg2 = buff[2];
            result = sum(arg1,arg2);
        } else if( fn == 2 ) {
            arg1 = buff[1];
            result = twice(arg1);
        } else {
            exit(EXIT_FAILURE);
        }
        buff[0] = result;
        // fprintf(stderr,"buff_value: %i,%i,%i \n",buff[0],buff[1],buff[2]);
        write_cmd(buff,1);
    }
}

/*
    read_cmd函数两次调用了read_exact
    例如标准输入里面有5个字节 {0,3,1,3,4}
    第一次调用 read(0,buf,2) ,读取了头两个字节{0,3}
    第二次调用 read(0,buf,3),读取了剩下的3个字节{1,3,4}
*/
int read_cmd(byte *buf) {
    int len;
    if( read_exact(buf,2) !=2 ) return(-1);
    // "<<" 左移 ,二进制的向左移8位,n<<8 十进制表示 n * 2^8 ;"|" 按位或
    len = (buf[0] << 8) | buf[1];
    return read_exact(buf,len);
}

// 从标准输入读取 len 个字节
int 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);
}

/*
例如:this->sum(3,4),返回结果{7,3,4},调用三次write_exact,分别输出{0,1,7},前两个字节是包头,表示消息体内容长度为1,之后的是消息体内容
*/
int write_cmd(byte *buf,int len) {
    byte li;
    li = (len >> 8) & 0xff; //  fprintf(stderr,"%d \n",li); out : 0
    write_exact(&li,1);
    li = len & 0xff; // fprintf(stderr,"%d \n",li); out : 1
    write_exact(&li,1);
    return write_exact(buf,len);
}

// 输出终端最多 len 个字节
int 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);
}

// 求和
int sum(int x,int y) {
    return x+y;
}

// 求2倍
int twice(int x) {
    return 3*x;
}
时间: 2024-10-12 19:51:52

Erlang调用C程序的相关文章

asp.net网页调用客户端程序

================================第一步:网注册表中(HKEY_CLASSES_ROOT)添加项 ================================第二步:在网页上写上标签调用 <a href="xishui://hello">zhangdi://hello</a> ================================显示效果:会弹出hello asp.net网页调用客户端程序,布布扣,bubuko.com

c# 调用外包程序 等待处理完成结果

string root = @"J:\yaoqianshu"; string pythonPath = "解压缩拷贝启动动画测试(新).py"; string ccccPath = ""; ProcessStartInfo myProcess = new ProcessStartInfo(); myProcess.WorkingDirectory = root; myProcess.FileName = pythonPath; Process o

Windows、Linux、Web安装及调用Matlab程序完整说明(大章)

本文档详细说明了Linux下Web项目调用Matlab函数的完整操作,文章适合对Java.Linux有一定基础了解的人群(不了解也没什么,无非是多试几次).因Linux作为服务器,所以未在其上安装Matlab主程序,只安装了运行环境MCR. 本文档内所述的所有版本软件均以32位为准,JDK与MCR也使用32位.若你的系统为64位,Linux系统同样为64位,则请尽量选择使用64位版本的JDK与MCR. 由于Matlab的版本限制问题,请保证Matlab主程序和MATLABCompiler Run

在C#中调用控制台程序

需求:  想在C#中调用一个带有参数 dos命令  whoami,并处理返回的文本信息 调查:  一查看 发现是个 .exe 的问件, 并且这个.exe可以根据不同的参数,得到不同的系统信息 解决方案:问度娘要了一点资料,度娘很爽快地答应了我,解决需求 参考的网页我放到了文章的末尾 关键代码: 新建了个窗体程序,代码在载入窗体的时候执行,只是个小demo,就不多说了 private void Form1_Load(object sender, EventArgs e)         { //实

【Qt】使用QProcess调用其它程序或脚本

大概试了一下,还是不错的,不过字符编码问题还不太好解决: 代码: #include "mainwindow.h" #include "ui_mainwindow.h" #include <QMessageBox> #include <QProcess> #include <QTextCodec> #include <QCloseEvent> MainWindow::MainWindow(QWidget *parent)

WEB程序调用客户端程序

最近一个项目中要点击WEB页面上的链接启动自己编写的程序,而且还要接收参数,google了1.5小时,终于初步试验通过了. 尝试google了:web send message windows form, bs call cs program, custom protocol...多个关键字组合,发现这种技术叫 registered URL protocol,在这篇文章里介绍得比较详细: http://msdn.microsoft.com/en-us/library/aa767914(v=vs.

[转]自定义URL Protocol Handler,从网页调用EXE程序

转自:http://www.cnblogs.com/zjneter/archive/2008/01/08/1030066.html 迅雷,电驴等软件可以在浏览器中点击一个url后自动启动,并执行操作.这是咋实现的呢? 要实现这个功能笼共分3步.(我们注册一个xishui:// 这样的 protocol-handler,实现在网页中点击xishui://hello,就弹出一个对话框,上面显示"hello")1 按照如下结构建立注册表  其中 [xishui] 是建立在注册表的 [HKEY

C#调用Exe程序示例

在编写程序时经常会使用到调用可执行程序的情况,本文将简单介绍C#调用exe的方法.在C#中,通过Process类来进行进程操作. Process类在System.Diagnostics包中. 示例一 using System.Diagnostics; Process p = Process.Start("notepad.exe"); p.WaitForExit();//关键,等待外部程序退出后才能往下执行 通过上述代码可以调用记事本程序,注意如果不是调用系统程序,则需要输入全路径. 示

Matlab调用C程序

Matlab是矩阵语言,如果运算可以用矩阵实现,其运算速度非常快.但若运算中涉及到大量循环,Matlab的速度令人难以忍受的.当必须使用for循环且找不到对应的矩阵运算来等效时,可以将耗时长的函数用C语言实现,并编译成Mex文件,Matlab便可以像调用内建函数一样调用C编写的函数.Mex文件其实是一种动态链接库,旧版本Matlab可以直接调用.dll,新版本要调用.mexw32或.mexw64文件. 编译过程需要C语言编译器,在Matlab中键入mex –setup进行安装与配置. MEX文件