﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-金庆的专栏-随笔分类-6. Erlang</title><link>http://www.cppblog.com/jinq0123/category/21068.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 05 Nov 2016 03:10:14 GMT</lastBuildDate><pubDate>Sat, 05 Nov 2016 03:10:14 GMT</pubDate><ttl>60</ttl><item><title> ejabberd为游戏免除注册限制</title><link>http://www.cppblog.com/jinq0123/archive/2016/11/03/214377.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 03 Nov 2016 04:11:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/11/03/214377.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214377.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/11/03/214377.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214377.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214377.html</trackback:ping><description><![CDATA[<div>20161103_ejabberd为游戏免除注册限制<br /><br />(金庆的专栏 2016.11)<br /><br />ejabberd聊天服务器默认会限制同一IP注册帐号须间隔600s。 <br />在游戏中需要为每个角色注册一个聊天帐号，不应该有此限制。 <br />可以更改服务器代码，为游戏服务器免除这一注册间隔时间。 <br /><br />假设游戏服用专用的帐号登录ejabberd, 然后为这种帐号免除注册限制。<br /><br />在ejabberd.yml配置访问控制列表(ACL)中添加 game_master：<br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; acl:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; game_master:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; user:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - "game_master_1@localhost"</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - "game_master_2@localhost"</span><br /><br />game_master 帐号预先创建，供游戏服务器登录ejabberd.<br /><br />mod_register的配置中，将 "access_from: deny" 改为 "access_from: all". <br />"access_from: deny" 表示任何用户都不能注册帐号，只能是登录前注册。 <br />"access_from: all" 表示登录用户也能注册帐号。 <br />这样game_master帐号先登录，然后就可以注册新帐号了。 <br /><br />添加 access_from_without_time_limit，允许game_master无注册限制。<br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; mod_register:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; access_from: all</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; access: register</span><br />&nbsp;&nbsp; &nbsp;<br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ## Allow some user register accounts without registration_timeout limit.</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; access_from_without_time_limit:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - allow: game_master</span><br /><br />实际上也可以这样直接配置： &nbsp;<br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; access_from_without_time_limit:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - allow:</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - user: game_master_1@localhost</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - user: game_master_2@localhost</span><br /><br />配置成 acl 的好处是，可以用<br /><br /><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; ejabberdctl reload_config</span><br /><br />重新加载 acl, 而模块配置部分无法重新加载。<br /><br />acl 配置还可以在 http admin 界面更改。<br /><br />代码需稍加更改，修改mod_register.erl.<br /><br />try_register/5 添加 From 参数改为 try_register/6<br /><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;try_register(User, Server, Password, From, SourceRaw, Lang)</span><br /><br />并将其中<br /><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;case check_timeout(Source) of</span><br /><br />改成<br /><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;CheckTimeout = case check_from_without_time_limit(From, Server) of</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;allow -&gt; true;</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;_ -&gt; check_timeout(Source)</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;end,</span><br /><span style="color: #800000;">&nbsp;&nbsp; &nbsp;case CheckTimeout of</span><br /><br />即如果From是gm帐号时，CheckTimeout直接通过，不再判断600s的间隔。<br /><br /><span>check_from_without_time_limit/2 仿照check_from/2，这样实现：</span><br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; check_from_without_time_limit(JID, Server) -&gt;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Access = gen_mod:get_module_opt(Server, ?MODULE, access_from_without_time_limit,</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fun(A) -&gt; A end,</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; none),</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; acl:match_rule(Server, Access, JID).</span><br />&nbsp;&nbsp; &nbsp;<br />添加：<br /><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; mod_opt_type(access_from_without_time_limit) -&gt;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fun acl:access_rules_validator/1;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; ...</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp; mod_opt_type(_) -&gt;</span><br /><span style="color: #800000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [..., access_from_without_time_limit, ...].</span><br />&nbsp;&nbsp;&nbsp;</div><img src ="http://www.cppblog.com/jinq0123/aggbug/214377.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-11-03 12:11 <a href="http://www.cppblog.com/jinq0123/archive/2016/11/03/214377.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ejabberd开发和部署</title><link>http://www.cppblog.com/jinq0123/archive/2016/10/31/214369.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 31 Oct 2016 09:13:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/10/31/214369.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214369.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/10/31/214369.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214369.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214369.html</trackback:ping><description><![CDATA[<div><div id="article_content"> <p>ejabberd开发和部署</p><p><br /></p><p>(金庆的专栏 2016.10)</p><p><br /></p><p>搭建了自己的ejabberd集群，然后少量更改源码，实现定制的XMPP服务器。</p><p>从github fork ejabberd 库，定为 master 分支跟踪原始库 master 分支，版本升级时从原库合并一次。</p><p>从16.09版本分一个 dev 分支，自己的代码就在这个 dev 分支上写。</p><p>服务器从源码编译安装。</p><p>代码更改后，make install, 然后 ejabberd restart, 或者 ejabberd update all.</p><p>如果有配置更改，则还要更改 /etc/ejabberd/ejabberd.yml.</p><p>未来主库版本升级后，可重新开个dev2分支，将dev的更改合并到dev2.<br /></p><p><br /></p>    </div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214369.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-10-31 17:13 <a href="http://www.cppblog.com/jinq0123/archive/2016/10/31/214369.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ejabberd mod_echo 解析</title><link>http://www.cppblog.com/jinq0123/archive/2016/08/26/214235.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 26 Aug 2016 11:02:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/08/26/214235.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214235.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/08/26/214235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214235.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214235.html</trackback:ping><description><![CDATA[<div><div id="article_content"> ejabberd mod_echo 解析<br /><br />(金庆的专栏 2016.8)<br /><br />按开发入门的说明，mod_echo是最简单的模块之一。<br />https://docs.ejabberd.im/developer/<br />当然 mod_hello_world 只有开始和结束日志，没有实际功能，比 mod_echo 更简单。<br /><br />配置说明一定要看，因为其中有模块功能的简介：<br />https://docs.ejabberd.im/admin/guide/configuration/#modecho<br /><br />没看功能简介，直接看代码，结果被 do_client_version/3 给引入了歧途。<br /><br />echo模块实现了echo功能，向特定域名的用户发送聊天消息，会原样返回。<br /><br />测试图：<br /><img alt="" src="http://www.cppblog.com/images/cppblog_com/jinq0123/echo.png" height="600" width="750" /><br /><br />echo域名是可配置的：<br /><br /><span style="color:#660000;">modules:<br />&nbsp; mod_echo:<br />&nbsp;&nbsp;&nbsp; host: "echo_x.mydomain"</span><br /><br />缺省为 "echo.@HOST@", 其中@HOST@会被替换成服务器域名。<br /><br />代码中的 do_client_version/3 演示了 route + receive 发送并收取应答，<br />但是与echo功能无关，可以忽略该函数。<br /><br />echo功能是 register_route/2 完成的，<br /><span style="color:#660000;">&nbsp; ejabberd_route:register_route(MyHost, Host)</span><br />表示从Host到MyHost的消息需要本模块来路由。<br />Host是服务器名，MyHost是配置的mod_echo.host.<br /><br />可以查看route表：<br /><span style="color:#000099;">(ejabberd@localhost)1&gt; ets:tab2list(route).<br />[{route,&lt;&lt;"pubsub.zt-2203857"&gt;&gt;,&lt;&lt;"zt-2203857"&gt;&gt;,&lt;0.5500.0&gt;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; undefined},<br />&nbsp;{route,&lt;&lt;"echox.zt-2203857"&gt;&gt;,&lt;&lt;"zt-2203857"&gt;&gt;,&lt;0.5492.0&gt;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; undefined},<br />&nbsp;{route,&lt;&lt;"conference.zt-2203857"&gt;&gt;,&lt;&lt;"zt-2203857"&gt;&gt;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;0.5445.0&gt;,undefined},<br />&nbsp;{route,&lt;&lt;"zt-2203857"&gt;&gt;,&lt;&lt;"zt-2203857"&gt;&gt;,&lt;0.5406.0&gt;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {apply,ejabberd_local,route}}]<br />(ejabberd@localhost)2&gt; <br /></span><br /><p>路由消息在 handle_info 中处理，它将来源和目的调换一下，然后调用 route() 发送原包。</p><p><br /></p><br /> </div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-08-26 19:02 <a href="http://www.cppblog.com/jinq0123/archive/2016/08/26/214235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ejabberd模块开发</title><link>http://www.cppblog.com/jinq0123/archive/2016/08/25/214231.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 25 Aug 2016 04:17:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/08/25/214231.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214231.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/08/25/214231.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214231.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214231.html</trackback:ping><description><![CDATA[<div>ejabberd模块开发<br /><br />(金庆的专栏 2016.8)<br /><br />参考：<br />https://docs.ejabberd.im/developer/modules/<br /><br />运行<br /><span style="color:#000099;">ejabberdctl modules_update_specs </span><br />会创建 C:\.ejabberd-modules\source\, 其中下载了<br />https://github.com/processone/ejabberd-contrib<br /><br />可以同样在sources目录下创建自己的模块代码，如：<br />$HOME/.ejabberd-modules/sources/mod_mysupermodule/<br /><br />运行<br /><span style="color:#000099;">ejabberdctl module_check mod_mysupermodule</span><br />可检查该目录是否符合模块规定(policy), 如:<br /><span style="color:#000099;"><span style="background-color: #ffffff;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl module_check mod_mysupermodule<br />Error: [{missing,"COPYING"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing,"README.txt"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing,"src (Erlang) or lib (Elixir) sources directory"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing_meta,url},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing_meta,home},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing_meta,summary},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {missing_meta,author}]</span></span><br /><br />需要COPYING和README.txt文件，src目录。<br />还有 mod_mysupermodule.spec 文件，仿照其他模块的例子写就行了，例如：<br /><span style="color:#660000;">url: "http://localhost"<br />summary: "My super m"<br />home: "http://localhost"<br />author: "Jin Qing"</span><br /><br />可以查看到可用模块：<br /><span style="color:#000099;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl modules_available<br />...<br />mod_mysupermodule&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; My super m<br />...</span><br /><br />即使没有任何源文件，也可以module_install.<br /><span style="color:#000099;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl module_install mod_mysupermodule<br /><br />ok</span><br /><br />更改 src\mod_mysupermodule.erl 后，无法再次安装：<br /><span style="color:#000099;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl module_install mod_mysupermodule<br /><br />Error: conflict</span><br /><br />好像可以用 module_upgrade：<br /><span style="color:#000099;"><span style="background-color: #ffffff;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl module_upgrade mod_mysupermodule<br /><br />src/mod_mysupermodule.erl:4: Warning: undefined callback function depends/2 (beh<br />aviour 'gen_mod')<br />src/mod_mysupermodule.erl:4: Warning: undefined callback function mod_opt_type/1<br />&nbsp;(behaviour 'gen_mod')<br />ok<br /><br />C:\Program Files\ejabberd-16.08\bin&gt;</span></span><br /><br />按文档说明，需要手工修改 <br />C:\Users\jinqing\AppData\Roaming\ejabberd\conf\ejabberd.yml<br />实际测试配置不需要手工修改，只需要创建 <br />C:\.ejabberd-modules\sources\mod_mysupermodule\conf\mod_mysupermodule.yml<br /><span style="color:#660000;"><br />modules:<br />&nbsp; mod_mysupermodule: {}<br /></span><br />按文件说明，需要手工复制编译生成的 <br />C:\.ejabberd-modules\mod_mysupermodule<br />到<br />C:\Program Files\ejabberd-16.08\lib\mod_mysupermodule<br />&nbsp; <br />查看代码，应该是会自动添加代码目录 <br />C:\.ejabberd-modules\mod_mysupermodule\ebin<br /><br />实际发现<br /><div><span style="color: #ff6600;">2016-08-24 16:27:54.016 [critical] &lt;0.550.0&gt;@gen_mod:start_module:162 Problem starting the module mod_mysupermodule for host &lt;&lt;"zt-2203857"&gt;&gt; </span><br /><span style="color: #ff6600;">&nbsp;options: []</span><br /><span style="color: #ff6600;">&nbsp;error: undef</span><br /><span style="color: #ff6600;">[{mod_mysupermodule,start,[&lt;&lt;"zt-2203857"&gt;&gt;,[]],[]},</span><br /><span style="color: #ff6600;">&nbsp;{gen_mod,start_module,3,[{file,"src/gen_mod.erl"},{line,154}]},</span><br /><span style="color: #ff6600;">&nbsp;{lists,foreach,2,[{file,"lists.erl"},{line,1337}]},</span><br /><span style="color: #ff6600;">&nbsp;{ejabberd_app,start,2,[{file,"src/ejabberd_app.erl"},{line,76}]},</span><br /><span style="color: #ff6600;">&nbsp;{application_master,start_it_old,4,</span><br /><span style="color: #ff6600;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"application_master.erl"},{line,273}]}]</span><br /><span style="color: #ff6600;">2016-08-24 16:27:54.016 [critical] &lt;0.550.0&gt;@gen_mod:maybe_halt_ejabberd:170 ejabberd initialization was aborted because a module start failed.</span><br /></div>是Windows下还有问题。<br /><br />需如下更改ext_mod.erl:<br /><span style="color:#660000;">modules_dir() -&gt;<br />&nbsp;&nbsp;&nbsp; DefaultDir = filename:join(getenv("HOME"), ".ejabberd-modules"),<br />-&nbsp;&nbsp; getenv("CONTRIB_MODULES_PATH", DefaultDir).<br />+&nbsp;&nbsp; getenv("CONTRIB_MODULES_PATH", filename:absname(DefaultDir)).</span><br /><br />不然add_patha/1会失败：<br /><span style="color:#660000;">code:add_patha("/.ejabberd-modules/mod_mysupermodule/ebin").</span><br /><br />然后重启(可能不需要)：<br /><span style="color:#000099;">C:\Program Files\ejabberd-16.08\bin&gt;ejabberdctl restart</span></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214231.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-08-25 12:17 <a href="http://www.cppblog.com/jinq0123/archive/2016/08/25/214231.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ejabberd编译更新脚本</title><link>http://www.cppblog.com/jinq0123/archive/2016/08/24/214228.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 24 Aug 2016 02:11:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/08/24/214228.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214228.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/08/24/214228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214228.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214228.html</trackback:ping><description><![CDATA[<div>ejabberd编译更新脚本<br /><br />(金庆的专栏 2016.8)<br /><br />用rebar编译ejabberd源码，然后复制编译所得beam文件到ejabberd安装目录，<br />调用ejabberdctl热更新。<br /><br /><span style="color: #800000; font-family: Courier;">call rebar compile skip_deps=true</span><br /><span style="color: #800000; font-family: Courier;">REM Need write right to ejabberd dir.</span><br /><span style="color: #800000; font-family: Courier;">copy ebin\*.beam "C:\Program Files\ejabberd-16.08\lib\ejabberd-16.08\ebin\"</span><br /><span style="color: #800000; font-family: Courier;">echo Update ejabberd.</span><br /><span style="color: #800000; font-family: Courier;">call "C:\Program Files\ejabberd-16.08\bin\ejabberdctl.cmd" update all</span><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-08-24 10:11 <a href="http://www.cppblog.com/jinq0123/archive/2016/08/24/214228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>搭建ejabberd集群</title><link>http://www.cppblog.com/jinq0123/archive/2016/08/19/214214.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Fri, 19 Aug 2016 09:14:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/08/19/214214.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214214.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/08/19/214214.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214214.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214214.html</trackback:ping><description><![CDATA[<div><div id="article_content"> 搭建ejabberd集群<br /><br />(金庆的专栏 2016.8)<br /><br />以2台机器搭建一个ejabberd集群。<br /><br />2台机器都是外网一块网卡，内网另一块网卡。<br />新建一个域名，添加2台机器的外网IP.<br /><br />分别用源码安装ejabberd，可以单机运行。<br /><br />复制 .erlang.cookie, 使2台机器都同。<br /><br />更改 /sbin/ejabberdctl<br />ERLANG_NODE=ejabberd@localhost 改为<br />ERLANG_NODE=ejabberd@192.168.7.160<br />即localhost改为内网IP<br /><br />启动失败：<br /><span style="color:#FFFFFF;"><span style="background-color: #000000;"><span style="color:#000099;"><span style="background-color: #ffffff;"><span style="font-family:Courier New;">[error] &lt;0.63.0&gt;@ejabberd_app:start_elixir_application:245 Elixir application not started.<br />[critical]  &lt;0.63.0&gt;@ejabberd_app:db_init:127 Node name mismatch: I'm  [ejabberd@192.168.7.160], the database is owned by [ejabberd@localhost]<br />[critical] &lt;0.63.0&gt;@ejabberd_app:db_init:129 Either set ERLANG_NODE in ejabberdctl.cfg or change node name in Mnesia<br />[error]  &lt;0.62.0&gt; CRASH REPORT Process &lt;0.62.0&gt; with 0 neighbours  exited with reason: node_name_mismatch in ejabberd_app:db_init/0 line  131 in application_master:init/4 line 134<br />[info] &lt;0.31.0&gt; Application ejabberd exited with reason: node_name_mismatch in ejabberd_app:db_init/0 line 131</span><br /></span></span><br /></span></span>因为Mnesia库中使用了旧的节点名<br /><span style="font-family:Courier New;color:#000099;">[root@host-192-168-7-160 ~]# ejabberdctl mnesia<br />[{auto_repair,true},<br />&nbsp;{backup_module,mnesia_backup},<br />&nbsp;{db_nodes,[ejabberd@localhost]},<br /></span><br />删除旧库。<br /><br /><span style="font-family:Courier New;color:#000099;">[root@host-192-168-7-160 ejabberd]# pwd<br />/var/lib/ejabberd<br />[root@host-192-168-7-160 ejabberd]# ls<br />caps_features.DAT&nbsp; muc_registered.DCD&nbsp;&nbsp; pubsub_index.DCD&nbsp;&nbsp;&nbsp; sr_group.DCD<br />DECISION_TAB.LOG&nbsp;&nbsp; muc_room.DCD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pubsub_item.DAT&nbsp;&nbsp;&nbsp;&nbsp; sr_user.DCD<br />irc_custom.DCD&nbsp;&nbsp;&nbsp;&nbsp; oauth_token.DCD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pubsub_node.DCD&nbsp;&nbsp;&nbsp;&nbsp; vcard.DAT<br />last_activity.DCD&nbsp; offline_msg.DAT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pubsub_state.DCD&nbsp;&nbsp;&nbsp; vcard_search.DCD<br />LATEST.LOG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; passwd.DCD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; roster.DCD<br />motd.DCD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; privacy.DCD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; roster_version.DCD<br />motd_users.DCD&nbsp;&nbsp;&nbsp;&nbsp; private_storage.DAT&nbsp; schema.DAT<br />[root@host-192-168-7-160 ejabberd]# rm -f *<br />[root@host-192-168-7-160 ejabberd]#<br /></span><br />更改 ejabberd.yml: <br /><span style="font-family:Courier New;color:#000099;">&nbsp;hosts:<br />&nbsp; - "my_domain.cn"<br />#&nbsp; - "localhost"</span><br /><br />先启动 ejabberd@192.168.7.160，然后启动另一节点，并让该节点加入集群：<br /><span style="font-family:Courier New;color:#000099;">ejabberdctl join_cluster 'ejabberd@192.168.7.160'</span><br /><br /><span style="font-family:Courier New;color:#000099;">[root@host-192-168-7-159 ejabberd]# ejabberdctl list_cluster<br />'ejabberd@192.168.7.160'<br />'ejabberd@192.168.7.159'<br />[root@host-192-168-7-159 ejabberd]#<br /></span><br />    </div>                                                                         </div><img src ="http://www.cppblog.com/jinq0123/aggbug/214214.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-08-19 17:14 <a href="http://www.cppblog.com/jinq0123/archive/2016/08/19/214214.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Windows编译ejabberd</title><link>http://www.cppblog.com/jinq0123/archive/2016/08/16/214181.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 16 Aug 2016 11:43:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/08/16/214181.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/214181.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/08/16/214181.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/214181.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/214181.html</trackback:ping><description><![CDATA[<div>Windows编译ejabberd<br /><br />(金庆的专栏)<br /><br />安装 erlang OTP. 添加路径到 PATH, 使 erl 可以运行。<br /><br />git clone ejabberd<br /><br />安装 rebar:<br />git clone git@github.com:rebar/rebar.git<br /><br /><span style="color:#000099;">E:\Git\rebar&gt;bootstrap.bat<br />escript: exception error: no match of right hand side value "找不到 E:\\Git\\reb<br />ar\\ebin\\rebar.beam\r\n"</span><br /><br />先创建 ebin\rebar.beam。见：https://github.com/rebar/rebar/issues/613<br /><br />复制生成的 rebar.cmd 到 ejabberd 目录。其实就几行代码：<br /><span style="color:#660000;">setlocal<br />set rebarscript=%~f0<br />escript.exe "%rebarscript:.cmd=%" %*<br /></span><br /><span style="color:#006600;">rebar.cmd get-deps</span><br /><br /><span style="color:#000099;">Cloning into 'p1_xmlrpc'...<br />Pulling luerl from {git,"https://github.com/rvirding/luerl",{tag,"v0.2"}}<br />Cloning into 'luerl'...<br />'sh' 不是内部或外部命令，也不是可运行的程序<br />或批处理文件。<br />ERROR: Command ['get-deps'] failed!</span><br /><br />更改 rebar.config.script，去除sh, 改为<br /><span style="color:#660000;"><span style="background-color: #ffffff;">{'get-deps', ""}</span><br /></span><br />将 ejabberd.app.src.in 复制为 ejabberd.app.src，更改其中的变量，<br /><span style="color:#000099;">E:\Git\ejabberd&gt;rebar compile skip_deps=true<br />==&gt; rel (compile)<br />==&gt; ejabberd (compile)</span><br /><br />deps 没有编译，可以使用安装包。<br />只需替换有更新的beam文件到安装目录。<br /><br />补充：<br /><div><span style="color: #000080;">E:\Git\ejabberd_jinq0123&gt;rebar compile skip_deps=true</span><br /><span style="color: #000080;">==&gt; rel (compile)</span><br /><span style="color: #000080;">==&gt; ejabberd_jinq0123 (compile)</span><br /><span style="color: #000080;">Compiled asn1/XmppAddr.asn1</span><br /><span style="color: #000080;">Compiled src/eldap_filter_yecc.yrl</span><br /><span style="color: #000080;">e:/Git/ejabberd_jinq0123/src/ejabberd_config.erl:none: undefined parse transform</span><br /><span style="color: #000080;">&nbsp;'lager_transform'</span><br /><span style="color: #000080;">ERROR: compile failed while processing E:/Git/ejabberd_jinq0123: rebar_abort</span><br /><br />须先用 rebar compile 编译 lager. 其他无法编译的可忽略，然后再</div><div><span style="color: #000080;">rebar compile skip_deps=true</span></div></div><img src ="http://www.cppblog.com/jinq0123/aggbug/214181.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-08-16 19:43 <a href="http://www.cppblog.com/jinq0123/archive/2016/08/16/214181.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang Port 小心换行</title><link>http://www.cppblog.com/jinq0123/archive/2016/01/20/212694.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 20 Jan 2016 06:46:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2016/01/20/212694.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/212694.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2016/01/20/212694.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/212694.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/212694.html</trackback:ping><description><![CDATA[<div><div id="article_content"> Erlang Port 小心换行<br /><br />(金庆的专栏)<br /><br />Erlang的Port接口使用cin, cout与外部Port进程通信。<br /><br />一般open_port()用binary模式打开。<br /><br /><span style="font-family:Courier New;color:#660000;">&nbsp;&nbsp;&nbsp; Port = open_port({spawn, PortExe},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{packet, 4}, binary, use_stdio]),<br /></span><br />此时须小心Port进程在Windows上输出 \n 前会自动添加 \r。<br />PortExe发送:<br /><span style="font-family:Courier New;">&nbsp;&nbsp; </span><span style="font-family:Courier New;color:#000066;">&lt;&lt;10,11,84,101,115,116,77,101,115,115,97,103,101,18,10,10,8,98,98,98,98,98,98,98,98&gt;&gt;</span><br />Erlang接收成为：&nbsp; &nbsp;<br /><span style="font-family:Courier New;color:#000066;">&lt;&lt;13,10,11,84,101,115,116,77,101,115,115,97,103,101,18,13,10,13,10,8,98,98,98,98,98&gt;&gt;</span><br /><br />需要将Port进程的stdin, stdout设为二进制模式：<br /><br /><span style="font-family:Courier New;color:#660000;">void set_binary_mode()<br />{<br />#if defined(WIN32)<br />&nbsp;&nbsp; &nbsp;int result;<br />&nbsp;&nbsp; &nbsp;result = _setmode(_fileno(stdin), _O_BINARY);<br />&nbsp;&nbsp; &nbsp;if (-1 == result)<br />&nbsp;&nbsp; &nbsp;{<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("set mode");<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br />&nbsp;&nbsp; &nbsp;}<br />&nbsp;&nbsp; &nbsp;result = _setmode(_fileno(stdout), _O_BINARY);<br />&nbsp;&nbsp; &nbsp;if (-1 == result)<br />&nbsp;&nbsp; &nbsp;{<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("set mode");<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br />&nbsp;&nbsp; &nbsp;}<br />#endif<br />}<br /></span><br />    </div>                                                                         </div><img src ="http://www.cppblog.com/jinq0123/aggbug/212694.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2016-01-20 14:46 <a href="http://www.cppblog.com/jinq0123/archive/2016/01/20/212694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IntelliJ Idea 设置 Dialyzer</title><link>http://www.cppblog.com/jinq0123/archive/2015/11/12/212247.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 12 Nov 2015 03:03:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/11/12/212247.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/212247.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/11/12/212247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/212247.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/212247.html</trackback:ping><description><![CDATA[<div>IntelliJ Idea 设置 Dialyzer<br /><br />(金庆的专栏)<br /><br />Erlang开发使用IDEA IDE可以设置外部工具Dialyzer, 然后就可以直接<br />Tools-&gt;External Tools -&gt; dialyzer 调用进行代码分析。<br /><br />配置方法为：<br />File | Settings | Tools | External Tools<br /><br />需要添加参数 -r $ProjectFileDir$/ebin<br /><br /><img alt="" src="http://www.cppblog.com/images/cppblog_com/jinq0123/IdeaToolsDialyzer.png" height="604" width="1377" /><br /><br />输出示例：<br />dialyzer -r D:\ServerSix/ebin<br />&nbsp; Checking whether the PLT C:\dailyzer_plt is up-to-date... yes<br />&nbsp; Proceeding with analysis...<br />b_pb.erl:81: Guard test is_list(Records::tuple()) can never succeed<br />b_pb.erl:85: Guard test is_list(Records::tuple()) can never succeed<br />b_pb.erl:90: Guard test is_list(Records::tuple()) can never succeed<br /><br />因为dialyzer输出有许多警告，我会将输出存为 dialyzer_output.txt, 加入SVN，<br />每次分析与上次分析仅需查看差异。</div><img src ="http://www.cppblog.com/jinq0123/aggbug/212247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-11-12 11:03 <a href="http://www.cppblog.com/jinq0123/archive/2015/11/12/212247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>emysql add_poop() 超时出错</title><link>http://www.cppblog.com/jinq0123/archive/2015/08/25/211674.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 25 Aug 2015 09:50:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/08/25/211674.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/211674.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/08/25/211674.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/211674.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/211674.html</trackback:ping><description><![CDATA[<div>emysql add_poop() 超时出错<br /><br />(金庆的专栏)<br /><br />sample/a_hello.erl 连接本机更改为连接局域网内的MySql服务器：<br /><br /><span style="font-family:Courier New;color:#660000;">&nbsp;&nbsp; &nbsp;emysql:add_pool(hello_pool, [{size,1},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {host, "192.168.1.2"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...</span><br /><br />编译运行时会出现超时退出：<br /><br /><span style="color:#000099;">D:\...\deps\emysql\samples&gt;erl -pa ../ebin -s a_hello run -s init stop -noshell<br />add_pool...{"init  terminating in  do_boot",{{nocatch,{failed_to_recv_packet_header,timeout}},[{init,start_it,1,[{file,"init.erl"},{line,1062}]},{init,start_em,1,[{file,"init.erl"},{line,1034}]}]}}<br /><br />Crash dump is being written to: erl_crash.dump...done<br />init terminating in do_boot ()<br /></span><br />设置 default_timeout 参数为 10s 就可以成功：<br /><span style="color:#000099;">D:\...\deps\emysql\samples&gt;erl -pa ../ebin -s a_hello run -s init<br />&nbsp;stop -noshell -emysql default_timeout 10000</span><br /><br />查看代码，缺省的 default_timeout 为8s。<br />当MySql没有skip-name-resolve时，连接MySql需要近10秒才能连上，<br />所以很容易出现超时错误。<br /><br />已提交问题：<br />https://github.com/Eonblast/Emysql/issues/174</div><img src ="http://www.cppblog.com/jinq0123/aggbug/211674.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-08-25 17:50 <a href="http://www.cppblog.com/jinq0123/archive/2015/08/25/211674.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang application stop 调用死锁</title><link>http://www.cppblog.com/jinq0123/archive/2015/08/06/211488.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 06 Aug 2015 02:30:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/08/06/211488.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/211488.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/08/06/211488.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/211488.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/211488.html</trackback:ping><description><![CDATA[<div>Erlang application stop 调用死锁<br /><br />(金庆的专栏)<br /><br />在application行为模块的start()中启动bson应用，在stop()中停止bson，<br />结果application:stop(bson)会死锁。<br /><br /><span style="color: #800000; font-family: Courier;">-module(my_app).</span><br /><span style="color: #800000; font-family: Courier;">-behaviour(application).</span><br /><br /><span style="color: #800000; font-family: Courier;">%% Application callbacks</span><br /><span style="color: #800000; font-family: Courier;">-export([start/2, stop/1]).</span><br /><br /><span style="color: #800000; font-family: Courier;">%% ===================================================================</span><br /><span style="color: #800000; font-family: Courier;">%% Application callbacks</span><br /><span style="color: #800000; font-family: Courier;">%% ===================================================================</span><br /><br /><span style="color: #800000; font-family: Courier;">start(_StartType, _StartArgs) -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; ok = application:start(bson),</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; {ok, Pid} = my_sup:start_link(),</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; {ok, Pid}.</span><br /><br /><span style="color: #800000; font-family: Courier;">stop(_State) -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; application:stop(bson),</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; ok.</span><br /><br />参考 How to stop third-party Erlang applications&nbsp;&nbsp; &nbsp;<br />http://stackoverflow.com/questions/2305511/how-to-stop-third-party-erlang-applications&nbsp;&nbsp; &nbsp;<br />才明白stop()是回调，在回调中试图停止其他应用就会死锁。<br />stop()是应用控制器回调的，应用控制器在等待回调返回时，无法响应application:stop()请求，所以死锁了。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/211488.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-08-06 10:30 <a href="http://www.cppblog.com/jinq0123/archive/2015/08/06/211488.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang简单并行服务器</title><link>http://www.cppblog.com/jinq0123/archive/2015/07/28/211398.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 28 Jul 2015 07:13:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/07/28/211398.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/211398.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/07/28/211398.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/211398.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/211398.html</trackback:ping><description><![CDATA[<div>Erlang简单并行服务器<br /><br />（金庆的专栏）<br /><br />Erlang并行服务器为每个Tcp连接创建对应的连接进程，处理客户端数据。<br /><br />参考 Erlang程序设计（第2版）<br />17.1.3 顺序和并行服务器<br /><br />并行服务器的诀窍是：每当gen_tcp:accept收到一个新连接时就立即分裂一个新进程。<br />为每个新套接字连接创建一个并行进程。<br /><br /><span style="font-family:Courier New;color:#660000;">-module(gs_svr).<br />-author("jinqing").<br /><br />-behaviour(gen_server).<br /><br />%% API<br />-export([start_link/0]).<br /><br />init([]) -&gt;<br />&nbsp;&nbsp;&nbsp; gs_listener:start_parallel(),<br />&nbsp;&nbsp;&nbsp; {ok, #{}}.<br /></span><br />gs_svr(GameServer gen_server)启动Tcp监听，并维护连接，如连接计数，发送广播。<br /><br />start_parallel()创建监听端口，然后创建连接进程。<br /><br /><span style="font-family:Courier New;color:#660000;">start_parallel() -&gt;<br />&nbsp;&nbsp;&nbsp; Port = server_csv:get_my_port(),<br />&nbsp;&nbsp;&nbsp; lager:info("Starting game server on port ~p...", [Port]),<br />&nbsp;&nbsp;&nbsp; {ok, ListenSocket} = gen_tcp:listen(Port,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [binary, {packet, 4},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {packet_size, 256 * 1024},&nbsp; % limit packet size<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {reuseaddr, true},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {nodelay, true},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {backlog, 999999},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {active, once}]),<br />&nbsp;&nbsp;&nbsp; connection:spawn_connection(ListenSocket).</span><br /><br />spawn_connection()创建连接进程。每接受一个连接就再创建一个新的连接进程。<br /><br /><span style="font-family:Courier New;color:#660000;">-module(connection).<br />-author("jinqing").<br /><br />%% API<br />-export([spawn_connection/1]).<br />-export([parallel_connect/1, loop/2]).<br /><br />-spec spawn_connection(ListenSocket :: gen_tcp:socket()) -&gt; pid().<br />spawn_connection(ListenSocket) -&gt;<br />&nbsp;&nbsp;&nbsp; spawn(fun() -&gt; ?MODULE:parallel_connect(ListenSocket) end).<br /><br />-spec parallel_connect(ListenSocket :: gen_tcp:socket()) -&gt; ok.<br />parallel_connect(ListenSocket) -&gt;<br />&nbsp;&nbsp;&nbsp; {ok, Socket} = gen_tcp:accept(ListenSocket),<br />&nbsp;&nbsp;&nbsp; spawn_connection(ListenSocket),<br />&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; gs_svr:cast_connection_new(self()),<br />&nbsp;&nbsp;&nbsp; ConnStat = conn_stat:new(),<br />&nbsp;&nbsp;&nbsp; erlang:send_after(1000, self(), timer_sec),<br />&nbsp;&nbsp;&nbsp; try ?MODULE:loop(Socket, ConnStat)<br />&nbsp;&nbsp;&nbsp; catch<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type:E -&gt; lager:error("loop() ~p:~p. ~p",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Type, E, erlang:get_stacktrace()])<br />&nbsp;&nbsp;&nbsp; end,<br />&nbsp;&nbsp;&nbsp; gs_svr:cast_connection_ended(self()),<br />&nbsp;&nbsp;&nbsp; ok.<br /><br />-spec loop(Socket :: gen_tcp:socket(), ConnStat :: conn_stat:conn_stat()) -&gt; any().<br />loop(Socket, ConnStat) -&gt;<br />&nbsp;&nbsp;&nbsp; receive<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {tcp, Socket, Bin} -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NewConnStat = rpc_handler:handle_bin(Socket, Bin, ConnStat),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inet:setopts(Socket, [{active, once}]),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NewConnStat2 = cutil_dos_checker:on_data(size(Bin), NewConnStat),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?MODULE:loop(Socket, NewConnStat2#{idle_sec=&gt;0});<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {tcp_closed, Socket} -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; save_on_end(ConnStat);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {tcp_error, Socket, Reason} -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; save_on_end(ConnStat);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {gs_to_connection, Msg} -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NewConnStat = handle_gs_msg(Msg, Socket, ConnStat),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?MODULE:loop(Socket, NewConnStat);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; timer_sec -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case conn_timer:timer_sec(ConnStat) of<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, NewConnStat} -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; erlang:send_after(1000, self(), timer_sec),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?MODULE:loop(Socket, NewConnStat);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Other -&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lager:error("Unknown msg: ~p", [Other]),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?MODULE:loop(Socket, ConnStat)<br />&nbsp;&nbsp;&nbsp; end.&nbsp; % This is tail-recursive.</span><br /><br />缺点是连接进程没有加入监控树。gs_svr出错重启时，连接进程connection应该断开并退出。</div><img src ="http://www.cppblog.com/jinq0123/aggbug/211398.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-07-28 15:13 <a href="http://www.cppblog.com/jinq0123/archive/2015/07/28/211398.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang的常驻模块与功能模块</title><link>http://www.cppblog.com/jinq0123/archive/2015/06/10/210867.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Wed, 10 Jun 2015 02:46:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/06/10/210867.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210867.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/06/10/210867.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210867.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210867.html</trackback:ping><description><![CDATA[<div>Erlang的常驻模块与功能模块<br /><br />Residence module<br /><br />The module where a process has its tail-recursive loop function(s).<br />If the tail-recursive loop functions are implemented in several modules, <br />all those modules are residence modules for the process.<br /><br />Functional module<br /><br />A module which is not a residence module for any process.<br /><br />Note that for a process implemented using an OTP behaviour, <br />the behaviour module is the residence module for that process. <br />The callback module is a functional module.<br /><br />常驻模块是指loop()函数所在模块，其他模块为功能模块。<br />对于OTP行为，行为模块是常驻模块，回调模块是功能模块。<br /><br />行为模块已由OTP实现。<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/210867.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-06-10 10:46 <a href="http://www.cppblog.com/jinq0123/archive/2015/06/10/210867.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang递归列举目录下文件</title><link>http://www.cppblog.com/jinq0123/archive/2015/05/05/210551.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 05 May 2015 09:11:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/05/05/210551.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210551.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/05/05/210551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210551.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210551.html</trackback:ping><description><![CDATA[<div>Erlang递归列举目录下文件<br />(金庆的专栏)<br /><br /><span style="color: #800000; font-family: Courier;">%%%-------------------------------------------------------------------</span><br /><span style="color: #800000; font-family: Courier;">%%% @author jinqing</span><br /><span style="color: #800000; font-family: Courier;">%%% @copyright (C) 2015, &lt;COMPANY&gt;</span><br /><span style="color: #800000; font-family: Courier;">%%% @doc 递归列举目录下的所有文件。</span><br /><span style="color: #800000; font-family: Courier;">%%%</span><br /><span style="color: #800000; font-family: Courier;">%%% @end</span><br /><span style="color: #800000; font-family: Courier;">%%% Created : 29. 四月 2015 16:02</span><br /><span style="color: #800000; font-family: Courier;">%%%-------------------------------------------------------------------</span><br /><span style="color: #800000; font-family: Courier;">-module(dir_util).</span><br /><span style="color: #800000; font-family: Courier;">-author("jinqing").</span><br /><br /><span style="color: #800000; font-family: Courier;">%% API</span><br /><span style="color: #800000; font-family: Courier;">-export([list_dir_recursive/1]).</span><br /><br /><span style="color: #800000; font-family: Courier;">%% 列举数据表目录下的所有文件，包括子目录中的。</span><br /><span style="color: #800000; font-family: Courier;">%% 返回文件名都带有 Dir 前缀，</span><br /><span style="color: #800000; font-family: Courier;">%% 如：["Dir/a.dat", "Dir/b/b.dat"]</span><br /><span style="color: #800000; font-family: Courier;">-spec(list_dir_recursive(Dir :: string()) -&gt; [string()]).</span><br /><span style="color: #800000; font-family: Courier;">list_dir_recursive(Dir) when is_list(Dir) -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; list_dirs_r([Dir], []).</span><br /><br /><span style="color: #800000; font-family: Courier;">%%%===================================================================</span><br /><span style="color: #800000; font-family: Courier;">%%% Internal functions</span><br /><span style="color: #800000; font-family: Courier;">%%%===================================================================</span><br /><br /><span style="color: #800000; font-family: Courier;">%% List recursively all files in dir/file list.</span><br /><span style="color: #800000; font-family: Courier;">%% Returns (files ++ Acc).</span><br /><span style="color: #800000; font-family: Courier;">list_dirs_r([] = _Files, Acc) -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; Acc;</span><br /><span style="color: #800000; font-family: Courier;">list_dirs_r([File | Tail] = _Files, Acc) -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; case filelib:is_dir(File) of</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; true -&gt; case file:list_dir(File) of</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {ok, NewFiles} -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FullNewFiles = [filename:join(File, N) || N &lt;- NewFiles],</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_dirs_r(FullNewFiles ++ Tail, Acc);</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {error, Reason} -&gt;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lager:error("List dir(~p): ~p", [File, Reason]),</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_dirs_r(Tail, Acc)&nbsp; % Ignore dir if error</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end;</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; false -&gt; list_dirs_r(Tail, [File | Acc])</span><br /><span style="color: #800000; font-family: Courier;">&nbsp;&nbsp;&nbsp; end.</span><br /><br />list_dirs_r()是尾递归。<br />列出当前目录下的所有文件和目录，放在Files变量中。<br />Acc是累加器，是一个列表，收集所有文件。<br />取Files中头部元素，如果是文件，则放入Acc结果集，继续处理余下的Files,<br />如果是目录，则列出该目录下所有，替换到 Files 头部。<br />性能消耗在<br />&nbsp;&nbsp;&nbsp; filename:join(File, N) <br />&nbsp;&nbsp;&nbsp; FullNewFiles ++ Tail<br /><br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/210551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-05-05 17:11 <a href="http://www.cppblog.com/jinq0123/archive/2015/05/05/210551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang标准数据结构的选择</title><link>http://www.cppblog.com/jinq0123/archive/2015/04/20/210401.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Mon, 20 Apr 2015 08:34:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/04/20/210401.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210401.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/04/20/210401.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210401.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210401.html</trackback:ping><description><![CDATA[<div>Erlang标准数据结构的选择<br /><br />（金庆的专栏）<br /><br />gen_server with a dict vs mnesia table vs ets<br />http://stackoverflow.com/questions/2154376/gen-server-with-a-dict-vs-mnesia-table-vs-ets<br />给出一个按应用类型选择的方法：<br /><br />Multiple processes on multiple VMs -&gt; mnesia<br />Multiple processes on one VM -&gt; ets/dets<br />One process -&gt; bag/dict/...<br /><br />Frequently Asked Questions about Erlang<br />February 22 2011<br />6.2&nbsp; Is there a collection of data structures, e.g. balanced trees?<br />http://ftp.sunet.se/pub/lang/erlang/faq/libraries.html#id55214<br />旧版FAQ中有以下说明：<br /><br />In practice, Erlang programs use lists (either natively or via dict) for data structures involving up to a few hundred elements and use ETS (the Erlang Term Store) or mnesia for anything larger. ETS uses hashing to allow near constant-time access to almost arbitrarily large amounts of data.<br /><br />For a collection of data consisting of a few (tens or hundreds) items, lists often outperform both ETS and trees. For large numbers of small items, ETS tends to work best. For larger items, balanced trees can outperform ETS because they avoid copying the data. <br /><br />但是新版FAQ中删除了以上这些说明，估计新版本中有了变化？<br /><br />Frequently Asked Questions about Erlang<br />April 20 2015<br />6.2&nbsp; Is there a collection of data structures, e.g. balanced trees?<br />http://www.erlang.org/faq/libraries.html#idp33085264<br /><br />Erlang开发建议(杂记版)<br />http://erlangdisplay.iteye.com/blog/374167<br />给出了根据规模选择的范围，应该是按旧版FAQ作出的：<br />Suggestion：<br />elments count: 0 － 100 | 100 - 10000&nbsp; |&nbsp; 10000 -<br />our select&nbsp;&nbsp; :&nbsp; list&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ets&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; gb_tree<br /></div><img src ="http://www.cppblog.com/jinq0123/aggbug/210401.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-04-20 16:34 <a href="http://www.cppblog.com/jinq0123/archive/2015/04/20/210401.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lager_transform未定义错误</title><link>http://www.cppblog.com/jinq0123/archive/2015/03/31/210211.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 31 Mar 2015 08:45:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/03/31/210211.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210211.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/03/31/210211.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210211.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210211.html</trackback:ping><description><![CDATA[<div>lager_transform未定义错误<br /><br />rebar编译时报错：<br /><span style="color:#000099;">D:\server\six&gt;d:/tools/rebar/rebar.cmd compile<br />==&gt; mysql (compile)<br />Compiling d:/server/six/deps/mysql/src/mysql_recv.erl failed:<br />d:/server/six/deps/mysql/src/mysql_recv.erl:none: undefined parse transform 'lager_transform'<br />d:/server/six/deps/mysql/src/mysql_recv.erl:12:<br />Warning: Non-UTF-8 character(s) detected, but no encoding declared. <br />Encode the file in UTF-8 or add "%% coding: latin-1" at the beginning of the file. <br />Retrying with latin-1 encoding.<br />ERROR: compile failed while processing d:/server/six/deps/mysql: rebar_abort<br /></span><br />lager_transform已加入erl_opts.<br />将lager在deps列表中提到第一位可解决。<br /><div><span style="color: #800000;">{erl_opts, [{parse_transform, lager_transform}]}.</span></div><span style="color:#660000;">%% lager must be the first to use lager_transform.<br />{deps, [{lager, ".*",&nbsp; {git, "https://github.com/basho/lager.git"}}, &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {mysql, ".*", {git, "https://github.com/dizzyd/erlang-mysql-driver.git"}} ...<br /></span><br />rebar仅仅是按依赖项顺序编译。<br />也可以预先编译lager，然后再rebar compile.<br /><br />参考：<br />http://stackoverflow.com/questions/20813513/configuring-lager-i-get-this-error-undefined-parse-transform-lager-transform</div><img src ="http://www.cppblog.com/jinq0123/aggbug/210211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-03-31 16:45 <a href="http://www.cppblog.com/jinq0123/archive/2015/03/31/210211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang edoc 多级目录出错</title><link>http://www.cppblog.com/jinq0123/archive/2015/03/26/210172.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Thu, 26 Mar 2015 09:07:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/03/26/210172.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210172.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/03/26/210172.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210172.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210172.html</trackback:ping><description><![CDATA[<div>Erlang edoc 多级目录出错<br /><br />使用rebar doc来生成项目文档。<br />但是当erl源文件目录src下建立子目录，并新建erlang文件后，就无法生成文档。<br /><p>例如，新建 src/tttt/, 并添加 dd_util.erl 文件。<br /></p><span style="color:#000099;">D:\six&gt;d:/tools/rebar/rebar.cmd doc<br />==&gt; six (doc)<br />ERROR: doc failed while processing D:/six: {'EXIT',{function_clause,[{edoc,expan<br />d_sources,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [[{tttt,"dd_util.erl","./src/tttt"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {'',"gateway_http.erl","./src"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {'',"six.erl","./src"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {'',"six_app.erl","./src"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {'',"six_sup.erl","./src"}],<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ".erl",<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {set,0,16,16,8,80,48,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {[],[],[],[],[],[],[],[],[],[],[],[],[],<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [],[],[]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {{[],[],[],[],[],[],[],[],[],[],[],[],<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [],[],[],[]}}},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [],[]],<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"edoc.erl"},{line,459}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {edoc,run,3,[{file,"edoc.erl"},{line,378}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_edoc,doc,2,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_edoc.erl"},{line,63}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_core,run_modules,4,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_core.erl"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {line,491}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_core,execute,6,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_core.erl"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {line,416}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_core,maybe_execute,8,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_core.erl"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {line,300}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_core,process_dir1,7,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_core.erl"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {line,259}]},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {rebar_core,process_commands,2,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [{file,"src/rebar_core.erl"},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {line,91}]}]}}<br /><br />D:\six&gt;<br /></span><br />在rebar.config中添加参数{packages, false}解决了。<br /><br /><span style="color:#660000;">{deps, [{mysql, ".*", {git, "https://github.com/dizzyd/erlang-mysql-driver.git"}},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {lager, ".*",&nbsp; {git, "https://github.com/basho/lager.git"}}, &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {mochiweb, ".*", {git, "https://github.com/mochi/mochiweb.git"}}]}.<br /><br />{erl_opts, [{parse_transform, lager_transform}]}.<br /><br />{edoc_opts, [{packages, false}]}.</span><br /><br />大概是Erlang多层目录会建立&#8220;subpackages&#8221;，应该就是模块名字空间：<br />If the source code is organized in a hierarchy of subdirectories although it does not use packages, use no_packages<br />但是没有找到相关的文档，不知道如何建立子包。<br /><br />参考：<br />http://www.erlang.org/documentation/doc-5.8.4/lib/edoc-0.7.8/doc/html/edoc.html#run-3<br />http://www.erlang.org/documentation/doc-5.8.4/lib/edoc-0.7.8/doc/html/chapter.html#Running_EDoc</div><img src ="http://www.cppblog.com/jinq0123/aggbug/210172.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-03-26 17:07 <a href="http://www.cppblog.com/jinq0123/archive/2015/03/26/210172.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Erlang 集群互连测试</title><link>http://www.cppblog.com/jinq0123/archive/2015/03/17/210071.html</link><dc:creator>金庆</dc:creator><author>金庆</author><pubDate>Tue, 17 Mar 2015 02:49:00 GMT</pubDate><guid>http://www.cppblog.com/jinq0123/archive/2015/03/17/210071.html</guid><wfw:comment>http://www.cppblog.com/jinq0123/comments/210071.html</wfw:comment><comments>http://www.cppblog.com/jinq0123/archive/2015/03/17/210071.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/jinq0123/comments/commentRss/210071.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/jinq0123/services/trackbacks/210071.html</trackback:ping><description><![CDATA[<div>Erlang 集群互连测试<br /><br />Erlang节点相同cookie全互联成为一个集群（cluster）.<br />如果2个集群不同cookie, 然后其中有节点连接到对方集群的节点，<br />这2个集群会合并成一个集群吗？<br /><br />连接到另一个集群时，需要先设置cookie，不然会被拒绝。<br /><span style="color:#660000;">erlang:set_cookie(Node2, DiffCookie)</span><br /><br />集群aaaa有节点a1, a2, cookie为 cookie_aaaa.<br />集群bbbb有节点b1, b2, cookie为 cookie_bbbb.<br /><br /><span style="color:#000099;"><span style="background-color: #ffffff;">&gt;erl -sname a1 -setcookie cookie_aaaa</span></span><br />...<br /><span style="color:#000099;">&gt;erl -sname a2 -setcookie cookie_aaaa<br />Eshell V6.3&nbsp; (abort with ^G)<br />(a2@jinqing)3&gt; net_adm:ping(a1@jinqing).<br />pong<br />(a2@jinqing)4&gt; nodes().<br />[a1@jinqing]</span><br /><br /><span style="color:#000099;">&gt;erl -sname b1 -setcookie cookie_bbbb</span><br />...<br /><span style="color:#000099;">&gt;erl -sname b2 -setcookie cookie_bbbb<br />(b2@jinqing)2&gt; net_adm:ping(b1@jinqing).<br />pong<br />(b2@jinqing)3&gt; nodes().<br />[b1@jinqing]</span><br /><br />bbbb节点无法直接连aaaa节点<br /><span style="color:#000099;">(b2@jinqing)4&gt; net_adm:ping(a1@jinqing).<br />pang</span><br /><br />b2节点更改cookie后，仍保持与b1的连接。<br /><span style="color:#000099;">(b2@jinqing)6&gt; erlang:get_cookie().<br />cookie_bbbb<br />(b2@jinqing)7&gt; erlang:set_cookie(node(), abcd).<br />true<br />(b2@jinqing)8&gt; erlang:get_cookie().<br />abcd<br />(b2@jinqing)9&gt; nodes().<br />[b1@jinqing]<br />(b2@jinqing)10&gt;</span><br /><br />b2设置cookie并连接a2后，b2进入了aaaa集群, 同时又在bbbb集群。<br /><span style="color:#000099;">(b2@jinqing)10&gt; erlang:set_cookie(node(), cookie_aaaa).<br />true<br />(b2@jinqing)11&gt; erlang:get_cookie().<br />cookie_aaaa<br />(b2@jinqing)12&gt; nodes().<br />[b1@jinqing]<br />(b2@jinqing)13&gt; net_adm:ping(a2@jinqing).<br />pong<br />(b2@jinqing)14&gt; nodes().<br />[b1@jinqing,a2@jinqing,a1@jinqing]<br />(b2@jinqing)15&gt;</span><br /><br />实际上是aaaa集群现有3个节点：a1, a2, b2.<br />bbbb集群仍然是2个节点：b1, b2.<br /><br /><span style="color:#000099;">(a1@jinqing)2&gt; nodes().<br />[a2@jinqing,b2@jinqing]</span><br /><br /><span style="color:#000099;">(a2@jinqing)5&gt; nodes().<br />[a1@jinqing,b2@jinqing]</span><br /><br /><span style="color:#000099;">(b1@jinqing)3&gt; nodes().<br />[b2@jinqing]<br /></span><br />此时 a2 ping b2 是通的，但是不会加入 bbbb 集群。<br /><span style="color:#000099;">(a2@jinqing)6&gt; net_adm:ping(b2@jinqing).<br />pong<br />(a2@jinqing)7&gt; nodes().<br />[a1@jinqing,b2@jinqing]<br />(a2@jinqing)8&gt;</span><br /><br /><p>结果是2个集群可以有交集。</p></div><img src ="http://www.cppblog.com/jinq0123/aggbug/210071.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/jinq0123/" target="_blank">金庆</a> 2015-03-17 10:49 <a href="http://www.cppblog.com/jinq0123/archive/2015/03/17/210071.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>