Erlang启动脚本

Erlang启动脚本

Erlang可以直接使用一个beam文件作为启动脚本

参见:https://stackoverflow.com/questions/1865997/erlang-startup-script

使用

erl -boot start_sasl -s XYZ_app start

即可在启动时启动sasl并执行XYZ_app的start函数

在start函数中执行一些无法在erl参数中执行的指令即可

比如ping指令、先行库启动指令,等等

而可以放在erl参数中的有detached、setcookie、name/sname、pa/pz、daemon、boot

 

注意:escript不能作为先行启动脚本使用,因为 escript执行完后会直接退出虚拟机而不会等待程序继续执行

erlang在OTP框架下的代码热更新

erlang在OTP框架下的代码热更新

网上有许多说原理的,但是却找不到一个完整的在OTP框架下的有关code_change函数用法的热更新

内容参考自以下网站与OTP文档
http://www.jiancool.com/article/61163151807/

实践了一下,关键的更新代码是这样

update() ->
sys:suspend(?SERVER),
code:purge(?MODULE),
code:load_file(?MODULE),
sys:change_code(?SERVER, ?MODULE, undefined, extraData),
sys:resume(?SERVER).

首先suspend暂停线程(change_code必须在暂停状态下使用。并且,暂停状态下线程不会响应call与cast,只会响应带外消息【所以主动模式TCP/UDP通信模块没法直接更新?】)
purge清除旧的模块代码(可选,但是如果不清除旧代码,在第二次更新是会出现not_purged错误并且更新失败)(其实是清除上一次更新后遗留下来的代码)(也可使用soft_purge进行软清除)
load_file加载新的代码文件
change_code调用对应进程的对应旧模块的新版本code_change回调函数来做一些转换操作(这里一般进行state状态量从旧版本到新版本的转换操作)(P:调用的是新代码的code_change函数,所以只要每次更新时在新代码中放置从旧代码到新代码的对state变量的转换函数即可)(网上就没有说清楚这个地方的)
最后调用resume恢复进程运行

Erlang分布式环境下注册名与调用方法

Erlang分布式环境下注册名与调用方法

在分布式环境下进行远程调用
标准的OTP模型是使用global参数注册server名,使用global参数进行调用

global注册时会将信息注册到kernel.global模块中.global模块会在分布式系统运行时运行

参见
kernel-3.2/doc/html/global.htmlstdlib-2.4/doc/html/gen_server.html#start_link-3
stdlib-2.4/doc/html/gen_server.html#cast-2

同样的,在gen_server文档中的一个细节是
如果start_link注册是使用的是global模式,在cast、call等调用时也要使用该模式才能正确调用

另:在不同节点上的代码要直接访问的部分一定要在调用节点本地有代码被加载,否则无法正确调用运行

下面的内容来自:https://veniceweb.googlecode.com/svn/trunk/public/daily_tech_doc/erlang_global_20091109.txt

 

重点介绍erlang的global模块.

1. 介绍:
这个全局服务是通过一个global_name_server的process来提供的,这个进程存在于每一个erlang node, 这个全局名字
服务在每个节点启动的时候自动启动.

这个模块在所有的链接的erlang节点的集群中实现了register_name/2和whereis_name/1的功能.一个注册名是一个pid的别名,
这个名字服务进程管理这些注册的pid,如果一个process终止,名字将自动被注销unregistered.

这些注册名储存在name table中,这个name table在每一个节点上都存在,因此名字服务的调用是快速的,当一个操作改变了
name table, 所有的节点的name table都会自动被更新.

2. 单个节点的例子:
-module(test).
-export([start/1, rpc_call/2, handle_msg/1]).

start(Name) ->
Pid = spawn(?MODULE, handle_msg, [Name]),
register(Name, Pid).          %% 在本地node注册process的名字

rpc_call(Name, Msg) ->
Name ! {Msg, self()},         %% 向本地node的process发消息
receive
{Reply, Name} ->
Reply
end.

handle_msg(Name) ->
receive
{stop, Pid} ->
Pid ! {stop, Name};
{Msg, Pid} ->
Pid ! {“received your msg: ” ++ Msg, Name},
handle_msg(Name)
end.

测试:
启动一个本地的process, 并注册一个名字pid1, 调用whereis/1测试,返回Pid,
测试通过名字pid1对进程发消息,
之后停止process, 再次调用whereis/1测试,返回undefined
test:start(pid1).
true
whereis(pid1).
<0.64.0>
test:rpc_call(pid1, “test – 1”).
“received your msg: test – 1”
test:rpc_call(pid1, “test – 2”).
“received your msg: test – 2”
test:rpc_call(pid1, stop).
stop
whereis(pid1).
undefined

3. Erlang Nodes集群的例子:
-module(test).
-export([start/2, rpc_call/2, handle_msg/1]).

start(Name, Node) ->
Pid = spawn(Node, ?MODULE, handle_msg, [Name]),
global:register_name(Name, Pid).    %% 注册global的process的名字

rpc_call(Name, Msg) ->
global:send(Name, {Msg, self()}),   %% 向global的name消息发送方式
receive
{Reply, Name} ->
Reply
end.

handle_msg(Name) ->
receive
{stop, Pid} ->
Pid ! {stop, Name};
{Msg, Pid} ->
Pid ! {“received your msg: ” ++ Msg, Name},
handle_msg(Name)
end.

测试:
在同一台机器上启动三个节点的erlang集群:
erl -sname node1 -setcookie testcookie
erl -sname node2 -setcookie testcookie
erl -sname node3 -setcookie testcookie
在node1上启动服务:
(node1@dev-pc)> test:start(pid1, node()).
yes
(node1@dev-pc)> test:rpc_call(pid1, “msg – 1”).
“received your msg: msg – 1”
在node2和node3上测试效果:
(node3@dev-pc)> test:rpc_call(pid1, “msg – 3”).
“received your msg: msg – 3”

(node2@dev-pc)> test:rpc_call(pid1, “msg – 2”).
“received your msg: msg – 2”

4. 分布式的知识补充:
<1> 如何在调用远程node上的方法?
rpc:call(Node, Mod, Func, [Arg1, … ArgN]).
会在Node上进行一次Mod:Func(Arg1, … ArgN)调用.

节点名的形式是: NodeName@Host, NodeName和Host都是atom(), 其实整个节点名就是一个atom().

<2> 在不需要DNS的情况下使用erl -sname node1,
需要DNS的情况下使用erl -name node2

<3> 设置cookie:
erl -setcookie testcookie
或者erlang:set_cookie(Node, testcookie)

<4> 如何保持两个node上的代码版本一致?
可以使用nl(Mod), 这个操作会使所有互联的节点上加载Mod.

<5> 判断节点的连通性: net_adm:ping(Node)

<6> node() -> Node 返回本地节点的名字
nodes() -> [Node] 返回网络上与当前节点连接的所有其它节点列表

有关Erlang分布式节点长名试验

有关Erlang分布式节点长名试验

节点名分长名与短名两种
节点名由前缀与后缀组成

本机唯一节点名(前缀)@本机地址(后缀)

对于cookie
两个几点连接时cookie必须一致 否则连接请求会被阻止

对于长名
节点名前缀在同一个机器上必须要唯一 即使同一机器上的多个节点后缀可以不同
节点长名后缀可使用可由DNS解析的域名或者直接为IP地址
当连接使用域名的节点会访问由DNS服务器解析的对应IP

当使用IP作为后缀时
使用net_adm:ping(‘长节点名’).建立连接时会连接到到对应的IP地址处
若目标节点后缀与目标IP不同时无法建立连接 即使是ping通后的自动建立全连通网络时也无法建立到错误的节点处
若使用127.0.0.1作为后缀 则只有本机节点能够连接到以127.0.0.1作为后缀的节点
若使用错误的IP地址 则无法接受ping 但其可以ping其他正确的节点 但在全连通过程中无法连接到其他设备的节点

“erlang-rfc4627”ErlangJson库windows7x64+msys2环境下构建与使用

“erlang-rfc4627”ErlangJson库windows7x64+msys2环境下构建与使用

erlang-rfc4627库GitHub链接

构建环境:
windows7 x64
msys2 64bit已预先在msys2中使用pacman装好GNU AutoMake
msys2启动脚本如下

@SET PATH=d:\Code\C++\x86_64-4.9.2-release-posix-seh-rt_v4-rev2\mingw64\bin;d:\Code\Erlang\erl6.4\bin;D:\Code\Perl64\site\bin;D:\Code\Perl64\bin
@SET CPLUS_INCLUDE_PATH=d:\Code\C++\x86_64-4.9.2-release-posix-seh-rt_v4-rev2\mingw64\opt;d:\Code\C++\x86_64-4.9.2-release-posix-seh-rt_v4-rev2\mingw64\opt\include
cd /d d:\
cd d:\Code\msys64\
msys2_shell.bat
pause

启动脚本中已配置好环境变量
包含常用的mingw-w64、shell脚本用perl、添加的erlang执行文件bin路径、mingw相关头文件搜索路径
设置好了msys2初始目录后
启动原生的msys2_shell启动脚本

附msys2中切换到D盘方法

cd /D/

其余操作与linux下一致

切换到rfc4627项目所在目录后
执行make指令 自动根据Makefile文件构建项目
使用make dist可构建文档

在erlang控制台(werl)使用cd(“路径”).切换工作路径到项目ebin文件夹
执行指令application:start(rfc4627_jsonrpc).启动jsonrpc应用程序
执行l(rfc4627).指令单独加载rfc4627解析模块