`
gashero
  • 浏览: 962728 次
  • 性别: 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 来规避一切缓存

相关推荐

    pickle:Erlang 库,用于在 Python 泡菜和 Erlang 术语之间进行转换

    为了使用这个库,开发者需要首先安装它,然后在 Python 代码中导入并调用相应的函数,将 Python 对象序列化为 pickle 格式,然后发送到 Erlang 系统,或者接收 Erlang 系统发送过来的数据,再反序列化回 Python 对象...

    Python-Director灵活快速和强大的Erlang流程管理库

    Director库将这些功能带入Python世界,使得Python开发者可以享受到Erlang OTP的优势,而无需深入学习Erlang语言本身。 以下是Director库的一些关键特性: 1. **进程模型**:Director库借鉴了Erlang OTP的进程模型...

    Python-inetsshdist一个运行在ssh上的Erlang发行版网络协议

    `Python-inetsshdist` 是一个独特的项目,它允许Erlang节点通过安全的Shell (SSH) 协议进行通信,从而扩展了Erlang分布式计算的能力。Erlang是一种面向并发的编程语言,其分布式特性使得在多节点间进行高效、可靠的...

    RabbitMQ 3.7安装及Python使用

    标题中提到了RabbitMQ 3.7的安装及Python使用,接下来详细阐述相关的知识点。 首先,RabbitMQ是一个开源的消息队列系统,它是基于高级消息队列协议(Advanced Message Queuing Protocol,简称AMQP)实现的。AMQP是...

    erlang programming

    Erlang是一种面向并发的、函数式编程语言,主要用于构建高度可扩展的、容错性强的分布式系统。在“erlang programming”这个主题下,我们可以深入探讨以下几个关键知识点: 1. **Erlang语言基础**:Erlang是瑞典...

    Python-Elarm是一个Erlang的报警管理器

    总结来说,Python-Elarm是Erlang生态系统中的一个重要工具,它提供了一种结构化、可扩展的方式来管理系统的报警和监控,有助于提高系统的稳定性和可靠性。对于任何使用Erlang进行开发的团队而言,理解并熟练运用...

    erlang版本的protobuf(erl_protobuffs)

    3. **集成性**:由于Erlang主要用于构建分布式系统,`erl_protobuffs`的设计考虑到了Erlang的通信模型,使得与其他Erlang进程的交互更为流畅,尤其适合处理大规模并发场景下的数据交换。 **使用erl_protobuffs** 1...

    RabbitMQ3.9.13和ErLang24.2版本

    5. **语言和库更新**:Erlang的新版本通常会包含语言特性的增强和库的更新,这些改进可能会间接影响到RabbitMQ的性能和功能。 在安装这两个软件时,首先需要下载Erlang的erlang_24.2.exe文件,安装后才能运行...

    rabbitmq,erlang安装包

    确保选择合适的安装路径,并勾选"Add Erlang environment variables to your system",这样可以将Erlang环境变量添加到系统中,便于后续RabbitMQ的识别。 2. **验证Erlang安装**:安装完成后,打开命令行窗口,输入...

    Erlang和RabbitMQ安装包

    4. **广泛的语言支持**:RabbitMQ提供了多种编程语言的客户端库,如Java、Python、Ruby、.NET等,便于开发者使用。 5. **持久化**:RabbitMQ可将消息持久化到磁盘,即使服务器重启,消息也不会丢失。 在提供的...

    基于Erlang VM的语言

    尽管Core Erlang对普通开发者来说较为晦涩,但它对于理解Erlang编译过程和进行编译器扩展非常有用。 【基于Erlang VM的语言示例】 1. **Reia**: Reia是一种类似于Ruby和Python的脚本语言,旨在提供更友好的语法...

    erlang17.3&rabbit3.4.1.zip

    RabbitMQ的基本工作原理是生产者(Producer)发送消息到交换机(Exchange),交换机根据预设的路由规则将消息路由到一个或多个队列(Queue)。消费者(Consumer)可以从队列中接收并处理消息。这种模式可以实现系统...

    仿知乎java源码-py_interface:Erlang到Python的集成:Python程序可以显示为Erlang节点

    【标题】中的“仿知乎java源码-py_interface:Erlang到Python的集成”表明这是一个关于Java编程的项目,其核心功能是实现Erlang与Python之间的交互。Erlang是一种面向并发、分布式计算的语言,常用于构建高可用性和...

    The Hacker's Guide to Scaling Python_Julien Danjou

    1. Python基础:本书可能会从Python的基础讲起,让读者对Python语言有更深入的理解,这对于理解和实践如何高效地使用Python扩展至关重要。 2. 性能分析与优化:书中可能会涉及到性能分析的工具和方法,帮助开发者...

    python读取excel表格生成erlang数据

    2. **创建新文件**:使用`file`函数创建一个`.erl`扩展名的新文件,并将处理后的Erlang数据写入该文件。 3. **文件路径管理**:合理规划文件路径,如`./server/`目录用于存放生成的Erlang文件,而`./dataxlsx/`目录...

    rabbitmq使用环境【安装包、Erlang环境】

    确保选择正确的安装路径,并勾选添加环境变量的选项,这样Erlang的bin目录会被添加到系统路径中,方便后续使用。 3. 验证安装:安装完成后,打开命令行窗口,输入`erl`命令,如果出现Erlang的shell界面,说明Erlang...

    ERLang+RabbitMQ安装包.rar

    Erlang是一种通用的、并发的、面向过程的编程语言,由瑞典电信设备制造商Ericsson开发,主要用于构建高度可靠、可扩展且容错的分布式系统。Erlang以其强大的并发处理能力、热代码升级功能以及内置的故障恢复机制在...

    Erlang和RabbitMQ

    RabbitMQ通过将消息缓存到消息队列中,解耦了生产者和消费者,使得系统更加灵活和可扩展。此外,RabbitMQ提供了多种工作模式,如简单模式、 direct模式、风扇型模式、主题模式等,以适应不同应用场景的需求。 安装...

    erlang和rabbitmq.zip

    【标题】"erlang和rabbitmq.zip" 涉及到的是两个关键技术:Erlang编程语言和RabbitMQ消息队列系统。Erlang是一种并发性极强、容错性出色的函数式编程语言,而RabbitMQ是基于Erlang开发的开源消息代理和队列服务器。 ...

    XP能用的erlang+rabbitMQ版本

    6. **语言支持**:RabbitMQ提供了各种编程语言的客户端库,如Java、Python、Ruby、JavaScript等,方便不同语言的开发者使用。 在Windows XP上安装otp_win32_R16B03.exe和rabbitmq-server-3.6.14.exe,用户可以构建...

Global site tag (gtag.js) - Google Analytics