`
gashero
  • 浏览: 943776 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Python扩展到Erlang

阅读更多

使用Python扩展到Erlang

作者: 日期:
gashero
2008-04-21

Erlang可以通过stdin/stdout与其他语言编写的进程交互,实现程序功能的扩展。这个例子使用了Python来扩展Erlang的功能,完善的演示了Erlang做扩展的方式和一些必要的工具函数。

这个例子使用line模式。

1   Erlang服务器

1.1   启动服务器

启动一个进程来连接到port,然后循环等待查询消息。

start() ->
    spawn(fun() ->
            register(expy,self()),
            process_flag(trap_exit,true),
            Port=open_port({spawn,"python -u client.py"},[{line,8}]),
            portloop(Port)
        end).

这里启动了一个进程,并且注册到名字expy。启动的命令为 python -u client.py

Note

程序的IO缓存,有些应用程序会对IO进行缓存处理,导致双方无法及时收到消息。对Python来说,可以用 -u 启动参数来关闭IO缓存。或者在程序中每次输出之后立即调用stdout的flush()方法。

1.2   停止服务器

只要给循环等待查询请求的进程发送stop消息即可,如下:

stop() ->
    expy ! stop,
    ok.

1.3   发送查询请求

因为本次例子以行模式运行,于是发送以行为单位的请求,发送到expy进程:

callline(Line) ->
    expy ! {call,{self(),Line++"\n"}},
    receive
        {reply,Data} ->
            Data;
        noreply ->
            io:format("callport no reply!~n");
        Other ->
            io:format("callport Other: ~p~n",[Other])
    end.

1.4   Port主循环

用于将查询请求转发给Port程序,接受port响应等。

portloop(Port) ->
    %io:format("PortLoop ready!~n"),
    receive
        {call,{Caller,Msg}} ->
            Port ! {self(),{command,Msg}},
            io:format("Sent message to python~n"),
            receive
                {Port,{data,{eol,Data}}} ->
                    %io:format("Reply: ~p~n",[Data]);
                    Caller ! {reply,Data},
                    portloop(Port);
                {Port,{data,{noeol,Part}}} ->   %会继续接受消息,直到最后一个是eol
                    %io:format("ReplyPart: ~p~n",[Part]);
                    io:format("long line~n"),
                    Line=recvlongline(Port,Part),
                    Caller ! {reply,Line},
                    portloop(Port);
                {'EXIT',Port,Reason} ->
                    io:format("Port exited: ~p~n",[Reason]),
                    unregister(expy),
                    Caller ! noreply,
                    exit(normal);
                Other ->
                    io:format("portloop 2 Other: ~p~n",[Other]),
                    Caller ! noreply
            end;
        stop ->
            Port ! {self(),close},
            receive
                {Port,closed} ->
                    unregister(expy),
                    exit(normal)
            end;
        {'EXIT',Port,Reason} ->
            io:format("Port exited: ~p~n",[Reason]),
            unregister(expy),
            %Caller ! noreply,
            exit(normal);
        Other ->
            io:format("portloop 1 Other: ~p~n",[Other])
            %portloop(Port)
    end.

顶层接受的消息的意义:

  1. {call,{Caller,Msg}} :查询请求,在循环内转发给Port之后等待Port的响应消息,并将结果发回给原来的调用者。
  2. stop :停止服务器,接受消息后停止服务器。
  3. {'EXIT',Port,Reason} :检测到Port主动停止的消息。
  4. Other :防止编程错误导致的错误消息无法捕捉。

1.5   消息的收发流程

向Port发送消息实际上是通过 Port ! {self(),{command,Msg}} 实现的。这样就把一行数据发送到了Port。

随后需要等待Port的响应消息,响应消息分为两种:

  1. {Port,{data,{eol,Data}}} :收到了完整的响应行数据,或者对于多块的响应,收到了最后一块。
  2. {Port,{data,{noeol,Data}}} :收到了不完整的一块数据。有后续数据需要继续等待消息。

因为行模式指定了最大一行允许接受的字符数量,那么在一行数据的长度超过这个数字时,就会导致消息被切分。每个收到的消息都是noeol类型,而最后一段完成整行的消息则是eol类型。

作为一种异常状况,应该考虑到行被切分的可能。

另外,就是Port可能会提前退出,这时会收到消息 {'EXIT',Port,Reason} 。可以自己定义处理,不过一般都需要注销对应进程,发送友好的回应,并且把自身进程结束掉。

1.6   被切分行的重新组装

一般按照需要决定是否还要组装对应的报文,所以这里定义了两个函数来接受超长的报文行,一种是接受并组装,另一种是接收后丢弃:

%% 持续接受超长的行
recvlongline(Port,LastLine) ->
    receive
        {Port,{data,{noeol,Data}}} ->
            %io:format("long part: ~p~n",[Data]),
            recvlongline(Port,LastLine ++ Data);
        {Port,{data,{eol,Data}}} ->
            LastLine ++ Data
    end.

%% 丢弃超长的行
droplongline(Port) ->
    receive
        {Port,{data,{noeol,_Data}}} ->
            droplongline(Port);
        {Port,{data,{eol,_Data}}} ->
            ok
    end.

2   Python客户端

客户端的 stdin 用于读取Erlang发来的命令,而 stdout 用于发送响应到Erlang。这个时候剩余的 stderr 可以用于打印自定义的错误消息,方便调试。

如下是完整的程序:

#! /usr/bin/env python
# -*- coding: UTF-8 -*-
# File: client.py
# Date: 2008-04-16
# Author: harry

"""
测试erlang与python的port
"""

import os
import sys
import time
import traceback

def process(line):
    try:
        bb=eval(line)
        return bb
    except:
        return repr(traceback.format_exc())

def lineio():
    while True:
        #print >> sys.stderr,'--'
        line=sys.stdin.readline().strip()
        #print >> sys.stderr, "Line:"+line
        if not line:
            #print >> sys.stderr, "break out"
            break
        if line=='exit':
            break
        #print >> sys.stderr,'++'
        reply=process(line)
        sys.stdout.write(str(reply)+"\n")
        sys.stdout.flush()
        #print >> sys.stdout,str(reply)+"\n"    #XXX: 这种不行
    return

def main():
    #print >> sys.stderr, 'python start!'
    lineio()
    return

if __name__=='__main__':
    main()

其中需要注意的是:

  1. 一般来说Port程序都是处于循环状态,接收Erlang发来的请求,处理并响应。而不应该处理完成后直接退出。
  2. 接收请求行时会得到行为有换行符的请求,注意去掉。
  3. 可以通过 stderr 打印错误调试信息。
  4. 发送响应报文时末尾要加上换行符。
  5. 响应报文本身注意对包含换行符情况的处理。
  6. 如果IO有缓存,那么可以选择关闭缓存,或者在写入响应后立即flush()。
1
0
分享到:
评论
1 楼 upsuper 2010-04-06  
python里可以使用 os.read 和 os.write 来规避一切缓存

相关推荐

    urusai:可扩展的Jabber(XMPP)机器人

    Urusai 0.1.1-dev 使用Python插件具有扩展性的Jabber(XMPP)机器人。软件需求Erlang R16B或更高版本的Python 2.7.x 汽车工具和钢筋建筑外部依赖安装 git clone ...

    轻松使用rabbitmq.rar

    RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展...

    SubEthaEdit-5.1.3.zip 可以写文章,代码,笔记

    SubEthaEdit附带了ActionScript,bash,C,C,CSS,ERB,Erlang,Go,HTML,Java,Javascript,JSON,LaTeX,Lua,Markdown,Objective-C,Perl,PHP,Python,Ruby,TOML和XML。您可以轻松地为自己选择的语言建立一...

    积分java源码-CreditsCSharpDemo:在C#中使用CREDITSAPI

    C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml 高效无缝交互的服务和 Delphi 等语言。 使用 Credits API 支持创建和执行交易(在 C# 中) _ 交易字段...

    Redis API文档 全称:Remote Dictionary Server 远程字典服务

    它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主...

    fiesta:从西班牙语到英语的统计机器翻译

    嘉年华:西班牙语到英语翻译 、 和 // 2015 年 2 月目录西班牙语句子我们的产出谷歌翻译输出 概述Fiesta 基于 IBM Model 1 Expectation Maximation 算法,并实施了几种特定于西班牙语的策略,以改进 IBM M1 算法产生...

    Redis-x64-3.0.500-rc1

    它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。[1] Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器...

    redis-core-java.zip

    它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。 [1] Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从...

    .emacs.d:我的emacs配置

    此配置为以下内容添加了改进的默认设置和扩展支持,从我使用它们的大致顺序(从最大到最小)列出了以下内容: Haskell / Purescript / Elm / OCaml Ruby / Ruby on Rails SQL CSS /更少/ SASS / SCSS Javascript / ...

    pfff:pfff主要是OCaml API,用于编写静态分析,动态分析,代码可视化,代码导航或保留样式的源到源转换,例如对源代码进行重构

    pfff pfff是一组工具和API,用于执行静态分析,代码可视化,代码导航或保留样式的源到源转换,例如对源... 另请参阅docs/manual/Parsing_xxx.pdf和docs/manual/Analyzis_xxx.pdf以获取有关如何使用或扩展pfff的更多文

    积分java源码-CreditsCPlusPlusDemoCMake:在C++(CMake)中使用CREDITSAPI

    积分java源码积分CPlusPlusDemoCMake 一个简单的控制台 C++ (CMake) 应用程序使用钱包的公钥显示...C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、 Cocoa、JavaScript、Node.js、Smalltalk、OCaml 和 D

    Sublime Text 3

    SublimeText2支持但不限于 C, C++, C#, CSS, D, Erlang, HTML, Groovy, Haskell, HTML, Java, JavaScript, LaTeX, Lisp, Lua, Markdown, Matlab, OCaml, Perl, PHP, Python, R, Ruby, SQL, TCL, Textile and XML 等...

    积分java源码-lookfor-api-csharp:寻找-api-csharp

    C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml 高效无缝交互的服务和 Delphi 等语言。 使用 Credits API 支持创建和执行交易(在 C# 中) _ 交易字段...

    Open with Overleaf-crx插件

    语言:English 使用www.overleaf.com... dat,.txt,.csv,.tsv源代码清单:.py,.m,.R,.rb,.erl(Python,MATLAB,R,Ruby,Erlang)。此扩展名是开源的。 源代码可在https://github.com/ishu3101/open-with-overl

    打开与Overleaf「Open with Overleaf」-crx插件

    dat,.txt,.csv,.tsv源代码清单:.py,.m,.R,.rb,.erl(Python,MATLAB,R,Ruby,Erlang)。此扩展名是开源的。源代码可在https://github.com/ishu3101/open-with-overleaf上找到。如果您喜欢此扩展,那么也请...

    SublimeText3(3083)带汉化包-注册码

    SublimeText2支持但不限于 C, C++, C#, CSS, D, Erlang, HTML, Groovy, Haskell, HTML, Java, JavaScript, LaTeX, Lisp, Lua, Markdown, Matlab, OCaml, Perl, PHP, Python, R, Ruby, SQL, TCL, Textile and XML 等...

    java代码生成器源码-pfff:用于代码分析、可视化或保留样式的源转换的工具

    C++、Rust、C#、Html、CSS、Erlang、Lisp、Haskell、Python、OPA 和 SQL。 对OCaml代码也有很好的支持,这样框架就可以用在pfff本身的代码上。 对于每种语言,主要有 2 个库,例如 parsing_php.cma 和 analysis_...

    神级代码编辑软件(Sublime Text 3) 3083 汉化 绿色 注册版

    SublimeText2支持但不限于 C, C++, C#, CSS, D, Erlang, HTML, Groovy, Haskell, HTML, Java, JavaScript, LaTeX, Lisp, Lua, Markdown, Matlab, OCaml, Perl, PHP, Python, R, Ruby, SQL, TCL, Textile and XML 等...

    Syntaxtic !「Syntaxtic!」-crx插件

    ts)VisualBasic(.vb)实验支持:Bibtex(.bib .bibtex)通用Lisp(.lisp .emacs)CSV漂亮打印使用适当的语法将自动突出显示以上述扩展名之一结尾的任何文件。 任何评论或建议都可以定向到...

    springCloud

    RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展...

Global site tag (gtag.js) - Google Analytics