从Java发送消息到已注册的Erlang gen_server

时间:2014-03-23 16:22:01

标签: erlang jinterface

如何从Jinterface Java服务器向全局注册的gen_server发送消息?

例如,我的gen_server就是这样开始的:

  start_link ({global, myServerName}, Mod, Args, Options).

mbox.send(“myServerName”,MyMessage)。不起作用。没有消息到达myServerName:handle_info。

1 个答案:

答案 0 :(得分:3)

一种方法是在服务器节点上调用global:send/2作为RPC。 Java代码如下所示:

import java.io.IOException;
import com.ericsson.otp.erlang.*;

public class JClient {
    static String server = "server";
    static String global = "myServerName";

    public static void main(String[] args) throws Exception {
        OtpSelf client = new OtpSelf("client", "java");
        OtpPeer peer = new OtpPeer(server);
        OtpConnection conn = client.connect(peer);
        conn.sendRPC("global", "send", new OtpErlangObject[] {
                new OtpErlangAtom(global),
                new OtpErlangTuple(new OtpErlangObject[] {
                        new OtpErlangAtom("publish"),
                        new OtpErlangTuple(new OtpErlangObject[] {
                                new OtpErlangAtom("all"),
                                new OtpErlangString("this is a test")})
                    })});
    }
}

OtpSelf构造函数的第二个参数是Erlang cookie,它必须与服务器节点的cookie匹配,如下所示。代码使用sendRPC OtpConnection方法调用服务器节点上的global:send/2函数,如果成功则返回全局注册进程的pid,否则返回错误(但是Java代码不检查这个。)

服务器可以是简单的gen_server,如下所示:

-module(svr).
-behaviour(gen_server).

-export([start_link/0, stop/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
         terminate/2, code_change/3]).

-record(state, {}).

start_link() ->
    gen_server:start_link({global, myServerName}, ?MODULE, [], []).

stop() ->
    gen_server:cast({global, myServerName}, stop).

init([]) ->
    {ok, #state{}}.

handle_call(_Request, _From, State) ->
    {reply, ok, State}.

handle_cast(stop, State) ->
    {stop, normal, State};
handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info({publish, {Topic, Msg}}, State) ->
    io:format("publish for topic ~p: ~p~n", [Topic, Msg]),
    {noreply, State};
handle_info(_Msg, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

请注意,我使用全局名称myServerName注册服务器以匹配您在问题中使用的名称,但实际上我从不使用类似的混合大小写原子名称。

要运行服务器,首先启动Erlang shell:

erl -sname server -setcookie java

请注意,cookie与Java代码中的内容相匹配,并且我使用-sname来命名服务器节点;我根本没有尝试长名。

然后,在Erlang shell中运行svr进程:

Erlang R16B03-1 (erts-5.10.4) [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false] [dtrace]

Eshell V5.10.4  (abort with ^G)
(server@myhost)1> svr:start_link().
{ok,<0.42.0>}

然后,运行Java客户端,服务器应发出以下消息:

publish for topic all: "this is a test"

这种方法的主要缺点是必须为每条消息通过RPC服务器。另一种方法是将RPC发送到global:whereis_name/1以查找已注册进程的pid,然后使用send而不是sendRPC直接向其发送消息,但缺点是如果全局注册的进程终止并重新启动,则Java代码将需要检测到pid不再有效并重做查找。

相关问题