如何在Erlang中创建多个用户并在它们之间进行通信

时间:2017-01-23 16:32:32

标签: oop erlang

让我们看看Java编程语言(作为一个例子),如果我想创建一个概念消息应用程序,它看起来就像这样:

class User {
    static List<User> users = new ArrayList();
    String name;

    User(String name) {
      this.name = name;
      users.add(this);
    }

    void sendMessage(String message) {
        for(User user : users) {
           user.messageReceived(message);
        }
    }

    void messageReceived(String message) { System.out.println(message); }

    String getName() { return name; } 
}

上面的代码只是为了说明如何使用多个可以相互通信的对象。

您可以执行以下操作来创建用户并发送消息:

User bob = new User("Bob");
User john = new User("John");
User anne = new User("anne");
bob.sendMessage("Hello World!"); 

所有已创建的用户都会收到bob的消息。

我正在尝试学习Erlang,并尝试重新创建这种类似的应用程序。我希望能够让不同的用户相互通信。

我尝试过很多东西:

-module(test).
-export([sendMessage/1]).

sendMessage(M) -> 
    io:format(M, []).

这样做只是将消息打印到控制台。我怎样才能拥有多个用户?

是否有某种模式或其他事情要做?

感谢您的时间:)

2 个答案:

答案 0 :(得分:2)

在你找到正确的入口点之前开始使用erlang并不容易,所以,虽然你的问题在我看来不是主题,但我会尝试给你一些信息和评论。

首先我建议您访问网站LearnYouSomeErlang,这是一个非常好的资源,可以使用真正的逐步方法开始使用erlang和函数式编程。我认为投资非常有价值,至少对我来说是这样。

下一步我已经评论了您的代码,并考虑了应该为erlang实现所做的更改。

class User {

Erlang中没有类概念,也没有对象。基本元素是一个进程(一个轻量级进程,完全独立于底层操作系统进程)。每个过程都有一个生命周期,在其生命周期中它能够维持一个状态。 这个状态可能是任何erlang术语,一旦进程死亡就会丢失。

static List<User> users = new ArrayList();

没有静态全局变量。维护一条信息的唯一方法是将其存储在进程状态, 显式地通过将状态作为服务器循环的参数传递,或者通过使用某些特殊存储(例如ETS或mnesia数据库)隐式地传递。 因此,要拥有包含用户名列表的内容,您需要,例如,注册为name_server的服务器进程在其状态中保存用户名列表。 在大多数情况下,应用程序确保在启动任何客户端之前启动所有必需的服务器。

String name;

流程能够维护信息。流程的基本结构是

  • 一个启动功能,负责产生该过程,
  • 负责初始化过程状态的init函数,
  • 和一个循环,它主要包含一个分析传入消息的接收块,根据收到的消息调用一些辅助函数,并通过调用自身以更新状态递归循环。

    用户(字符串名称){   this.name = name;   users.add(本); }

构造函数由2个函数start和init替换。启动函数在OOP中没有真正的等价,除了它依赖于系统为内部数据,消息队列,堆栈分配必要的内存......与java或C ++中对象属性的自动内存分配相当。然后,它在VM调度程序中注册该进程。 init等同于用户定义的构造函数。

void sendMessage(String message) {
    for(User user : users) {
       user.messageReceived(message);
    }
}

以这种方式编写,sendMessage函数不依赖于它在执行时所属的对象实例,因为它只使用类的静态数据。因此,最接近的转换可以是名称服务器的接口。接口通常是属于服务器模块(相同文件!)的代码段,为其他模块导出,并在客户端进程上下文中执行。接口向服务器发送消息(其主要作用是隐藏与服务器的通信协议),如果访问是同步的(或不是),则等待响应(或不响应)。在真实的通信应用程序中,请求应来自用户,由系统中的进程表示,并且流程看起来更像:

  • 用户使用外部接口(GUI程序,shell,Web界面......)向其图像处理发送请求
  • 用户进程要求名称服务器提供所有必要信息以访问收件人
  • 用户进程使用用户界面发送消息

也可以使用名称服务器直接发送消息

void messageReceived(String message) { System.out.println(message); }

String getName() { return name; }

这两个最后的函数是用户进程中的辅助函数,它们在消息接收时触发。

最后,如果您有兴趣,我在github minichat上放了一个聊天系统示例,这个示例相当简单,并说明了此处讨论的所有内容(以及更多内容)并包括文件和评论。

答案 1 :(得分:0)

-module(chat).
-export([new/1, delete/1, send/3]).
-export([init_user/1]).

new(UserName)->
        spawn(?MODULE, init_user, [UserName]).
delete(Pid)->
        Pid ! stop.
send(From, To, Message)->
        To ! {message, From, Message}.
init_user(UserName)->
        io:format("Starting Client ~w with user name ~w~n",[self(), UserName]),
        wait_for_message(UserName).

wait_for_message(UserName)->
        receive
                {message, From, Message}->
                        io:format("Got Message From ~w And Message: ~s~n",[From, Message]),
                        wait_for_message(UserName);
                stop->
                        io:format("Stoping~w~n",[self()]);
                Message->
                        io:format("Unhandled Message:~w~n",[Message]),
                        wait_for_message(UserName)
        end.

模拟进程间的通信示例: -

c(chat).
Bob = chat:new("Bob").
John = chat:new("John").
Anne = chat:new("Anne").
chat:send(Bob, John, "Hello World!!").