Keep in mind while reading this that you should really find a way to update your existing service to keep up to date with newer runtimes. I've dealt with being stuck on a legacy runtime only because someone thought they needed to fork a particular module somewhere in a way that made it impossible to upgrade -- and that was just a nightmare.*
TL;DR: (But you should read it anyway)
Yes, I just confirmed that you can connect an R17 and an R20 node via disterl and send messages: R17 node:
ceverett@changa:/opt/erlang/R17.5/bin$ ./erl -name bar -cookie walnut
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V6.4 (abort with ^G)
(bar@changa.shinden.tsuriai.jp)1> P = spawn(fun Wait() -> receive {From, Message} -> From ! {received, Message}, Wait() end end).
<0.44.0>
(bar@changa.shinden.tsuriai.jp)2> global:register_name(waiter, P).
yes
Note that above the R20 node was started first, so that was the version of EPMD that was running. I have no idea whether that would matter, nor do I know if EPMD has changed between R17 and R20. This is all undocumented functionality. Read below for a much more future-proof way to do this. The documented way to connect two nodes of different versions is with the +R runtime flag. I regard this as a wildly unreliable hack (precisely as unreliable as what I demonstrated above) unless you've tested it thoroughly first -- and it may have unintended side effects depending on the versions involved (and no telling what is coming in the future). But this is an actual runtime flag and it obviously exists for a reason. See legoscia's answer for more detail about this.
Discussion
Whether or not two versions of Erlang's runtime are compatible over disterl, writing network applications in Erlang is really easy. You can always connect two of any different things over TCP. The simple solution to this would be to write a network application in Erlang using the current version of Erlang (R20.1 at the moment) that receives Apple voip pushes, and forwards them to your main application. Write:
A single TCP socket handling process inside your R17 system.
The Apple VOIP push service handler in R20 and a TCP socket connecting process that talks to the R17 TCP socket handler.
Treat the Apple VOIP service within your system as if it exists as a native part of your application. The socket handler in the R17 node is the VOIP service. Make sure you write its interface functions with that in mind -- later if you can migrate your code to R20 then you won't have to worry with this detail because it will be already abstracted by the internal protocol in Erlang. As for the push updates themselves, you can create whatever sort of protocol you want. Erlang's external term format has not changed between R17 and R20, so you will be able to send native messages between the two nodes by having the Apple VOIP side socket handler (on the R20 node) do something like:
I just happen to most often see socket handling processes as proc_lib processes instead of gen_servers most of the time. But it doesn't matter in most cases. Another approach is to use binaries:
loop(Parent, Debug, State = #s{socket = Socket}) ->
receive
{tcp, Socket, <<"PUSH ", VOIP_Data/binary>>} ->
{ok, NewState} = do_stuff(VOIP_Data, State)
loop(Parent, Debug, NewState);
%% Your other stuff
%% OTP system stuff
end.
It really depends on the nature of VOIP_Data . If it is a binary itself and the R20 Apple push service should just pass it along without inspecting it, then the raw binary method is easy. If the R20 side is going to be interpreting the message and converting it to an Erlang message of its own then you'll do much better with the binary_to_term/1 / term_to_binary/2 form.
2条答案
按热度按时间rur96b6h1#
TL;DR: (But you should read it anyway)
Yes, I just confirmed that you can connect an R17 and an R20 node via disterl and send messages:
R17 node:
R20 node:
Note that above the R20 node was started first, so that was the version of EPMD that was running. I have no idea whether that would matter, nor do I know if EPMD has changed between R17 and R20.
This is all undocumented functionality. Read below for a much more future-proof way to do this.
The documented way to connect two nodes of different versions is with the
+R
runtime flag. I regard this as a wildly unreliable hack (precisely as unreliable as what I demonstrated above) unless you've tested it thoroughly first -- and it may have unintended side effects depending on the versions involved (and no telling what is coming in the future). But this is an actual runtime flag and it obviously exists for a reason. See legoscia's answer for more detail about this.Discussion
Whether or not two versions of Erlang's runtime are compatible over disterl, writing network applications in Erlang is really easy. You can always connect two of any different things over TCP.
The simple solution to this would be to write a network application in Erlang using the current version of Erlang (R20.1 at the moment) that receives Apple voip pushes, and forwards them to your main application.
Write:
Treat the Apple VOIP service within your system as if it exists as a native part of your application. The socket handler in the R17 node is the VOIP service. Make sure you write its interface functions with that in mind -- later if you can migrate your code to R20 then you won't have to worry with this detail because it will be already abstracted by the internal protocol in Erlang.
As for the push updates themselves, you can create whatever sort of protocol you want.
Erlang's external term format has not changed between R17 and R20, so you will be able to send native messages between the two nodes by having the Apple VOIP side socket handler (on the R20 node) do something like:
And on the receiving node (the R17 node):
You could write the R17 side as a gen_server also, listening for:
I just happen to most often see socket handling processes as
proc_lib
processes instead of gen_servers most of the time. But it doesn't matter in most cases.Another approach is to use binaries:
And on the receiving node (the R17 node):
It really depends on the nature of
VOIP_Data
. If it is a binary itself and the R20 Apple push service should just pass it along without inspecting it, then the raw binary method is easy. If the R20 side is going to be interpreting the message and converting it to an Erlang message of its own then you'll do much better with thebinary_to_term/1
/term_to_binary/2
form.mznpcxlj2#
也许吧
zxq9's answer显示了它实际上是有效的,同时也建议了一种替代方法。这个答案更一般地讲了使用Erlang发行版连接两个不同的发行版。
在the
erl
man page中,您可以找到+R
标志:+R ReleaseNumber
设置兼容模式。
默认情况下,分发机制不向后兼容。此标志将模拟器设置为与早期Erlang/OTP版本
ReleaseNumber
兼容的模式。版本号必须在<current release>-2..<current release>
范围内。这将限制模拟器,使其可以与运行该早期版本的Erlang节点(以及C和Java节点)通信。确保分布式Erlang系统的所有节点(Erlang-、C-和Java节点)都是同一Erlang/OTP版本,或者来自两个不同的Erlang/OTP版本X和Y,其中所有Y节点都具有兼容模式X。
这反映了手册的"兼容性"部分所述内容:
Erlang节点可以在至少两个先前版本和两个后续版本之间进行通信。
因此,理论上,如果19节点以
+R 17
标志启动,Erlang 17和19应该能够通信。但事实上,这个标志目前并没有打开任何兼容性特性(参见源代码),而且自从R16B中的compatibility for R9 was removed以来,它就没有这样做过。X版本和Y版本是否可以相互连接的答案是"试试看"。
另请参阅this answer,以获取显示不同Erlang版本之间连接的表格。