您的位置:首页 > Web前端 > Node.js

用Pomelo 搭建一个简易的推送平台

2013-06-18 02:36 471 查看
<h2 id="menuIndex0">前言</h2> <p>实际上,个人感觉,pomelo 目前提供的两个默认<code>sioconnector</code>和<code>hybridconnector</code> 使用的协议并不适合用于做手机推送平台,在pomelo的一份公开ppt里面,有提到过, 网易的消息推送平台是基于pomelo开发的 (一个frontend 支持30w 长连接,消耗了3g 内存,如果我没记错数据应该是这样),不过,这里用的前端(frontend)实现的是基于MQTT协议,我估计这个基于MQTT协议实现的frontend,基本不可能开源出来.这里只是说,默认提供的frontend不适合用于构建大型的推送平台(c10m规模的),一般而言(c10k级别的),个人感觉还是够用的.</p> <p>为了展示,更多pomelo 的相关特性,可能这里的逻辑业务,与实际有所不同.敬请注意</p> <p><a name="more"></a></p> <h2 id="menuIndex1">推送平台的架构图</h2> <p>整个应用的架构图:</p> <blockquote> <p><a href="http://static.oschina.net/uploads/img/201306/18023619_2bwZ.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pushapp" border="0" alt="Pushapp" src="http://static.oschina.net/uploads/img/201306/18023619_OA9j.png" width="204" height="244" /></a> </p> </blockquote> <h3 id="menuIndex2">后端</h3> <ul> <li>pomelo@0.4.3 </li> </ul> <h3 id="menuIndex3">前端</h3> <ul> <li>android </li> <li>web browser </li> </ul> <h2 id="menuIndex4">开发约定</h2> <h3 id="menuIndex5">客户端请求对象</h3> <p></p> <figure class="highlight lang-js"> <table><tbody> <tr> <td class="gutter"> <pre>1
2
3
4
5</pre>
</td>

<td class="code">
<pre>{
<span class="string">"role"</span>: <span class="string">"client/server"</span>,
<span class="string">"apikey"</span>: <span class="string">"String"</span>,
<span class="string">"clientId"</span>: <span class="string">"String"</span>

}</pre>
</td>
</tr>

</tbody></table>
</figure>

<p></p>

<h3 id="menuIndex6">服务端返回对象</h3>

<p><strong>发给web management</strong></p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4
5</pre>
</td>

<td class="code">
<pre>{
<span class="string">"code"</span>: <span class="string">"Int httpCode ex: 200"</span>,
<span class="string">"msg"</span>: <span class="string">"String"</span>,
<span class="string">"users"</span>: <span class="string">"Array 客户端的clientId 值 ex:["</span>android1<span class="string">"] "</span>

}</pre>
</td>
</tr>

</tbody></table>
</figure><strong>发给android客户端</strong>

<p></p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4</pre>
</td>

<td class="code">
<pre>{
<span class="string">"code"</span>: <span class="string">"Int httpCode ex: 200"</span>,
<span class="string">"msg"</span>: <span class="string">"String"</span>

}</pre>
</td>
</tr>

</tbody></table>
</figure>

<p></p>

<h3 id="menuIndex7">客户端访问用的route</h3>

<p>android:</p>

<p>connector route = sio-connector.entryHandler.enter, 用于把当前客户端加入到推送频道当中</p>

<p>WebManagement:</p>

<p>connector route = hybrid-connector.entryHandler.enter,用于连接服务器.
<br />backend route = pushserver.pushHandler.pushAll, 把消息推送到所有已连接的客户端.</p>

<h2 id="menuIndex8">后台编码</h2>

<p>Pomelo 有个特点,就是约定开发,很多地方是约定好的配置,优点是,架构清晰,可读性好,缺点是,需要大量的文档支持,目前而言,pomelo的官方文档做的不好的地方就是,虽然文档都有了,但是太零散了,分类不清楚,还有就是文档没跟上开发,有时候,你不阅读里面源码根本不知道这个api要传那些参数.</p>

<h3 id="menuIndex9">sioconnector / hybridconnector</h3>

<p>由于pomelo 0.3 以后新增了一个新的connector:hybridconnector,支持socket和websocket,使用二进制通讯协议,但是除了,网页js版本和c 客户端实现了这个connector,其他客户端均还没实现,所以,我们还需要一个兼容android 客户端的connector: siocnnector,关于两个connector 具体比较,以后有空重写<a href="http://blog.gfdsa.net/2013/06/04/pomelo_study_two/">这篇的时候</a>,暂时,你只要知道,这个两个connector,一个基于socket.io,一个基于socket和websocket 即可.</p>

<p><strong>app.js</strong> 由于我们用到了两个不同的connector,所以要在app.js写上:</p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19</pre>
</td>

<td class="code">
<pre><span class="comment">// 支持 socket.io</span>

app.configure(<span class="string">'production|development'</span>, <span class="string">'sio-connector'</span>, <span class="keyword">function</span>(){
app.set(<span class="string">'connectorConfig'</span>,
{
connector : pomelo.connectors.sioconnector
});
});

<span class="comment">//支持 websocket 和 socket</span>
app.configure(<span class="string">'production|development'</span>, <span class="string">'hybrid-connector'</span>, <span class="keyword">function</span>(){
app.set(<span class="string">'connectorConfig'</span>,
{
connector : pomelo.connectors.hybridconnector,
heartbeat : <span class="number">300</span>,
useDict: <span class="literal">true</span>,
useProtobuf: <span class="literal">true</span>

});

});</pre>
</td>
</tr>

</tbody></table>
</figure>经过这样的配置,我们就能够使用两个不同的connector了.

<p></p>

<h3 id="menuIndex10">推送实现</h3>

<p>用pomelo 进行消息的推送,非常便捷,由于,我们现在只关注推消息给全部客户端,那样就非常简单了.</p>

<p>推送流程:</p>

<ul>
<li>根据uuid 把 android 客户端添加到各自的推送频道当中. </li>

<li>web 端根据uuid 把消息推送的全部在线的客户端. </li>
</ul>

<p><strong>为了教学的方便,这里的uuid 硬编码为: xxx-xx--xx-xx</strong></p>

<p>把客户端添加到相应的channel</p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre>
</td>

<td class="code">
<pre><span class="comment">//把客户端添加到推送列表中</span>

PushRemote.prototype.add = <span class="keyword">function</span>(uid, role, sid, channelName, cb){
<span class="keyword">var</span> channel = <span class="keyword">this</span>.channelService.getChannel(channelName, <span class="literal">true</span>);
<span class="keyword">if</span>(role === <span class="string">'server'</span>){
<span class="comment">//web 服务端直接返回用户列表</span>
cb(<span class="literal">null</span> ,<span class="keyword">this</span>.getUsers(channelName));
}<span class="keyword">else</span> {
<span class="keyword">if</span>(!!channel){
channel.add(uid ,sid);
}
<span class="comment">//uuid 告诉给服务端onAdd 事件</span>
<span class="comment">// [{uid: userId, sid: frontendServerId}]</span>
<span class="keyword">var</span> server = [{uid: channelName, sid: sid}];
<span class="keyword">this</span>.channelService.pushMessageByUids(<span class="string">'onAdd'</span>, {msg: <span class="string">"add ok"</span>, users:<span class="keyword">this</span>.getUsers(channelName)},server, <span class="keyword">function</span>(err){
<span class="keyword">if</span>(err){
console.log(err);
<span class="keyword">return</span>;
}
});
}
};</pre>
</td>
</tr>

</tbody></table>
</figure>Frontend 利用rpc 调用pushserver 添加客户端到相应频道的方法.

<p></p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13</pre>
</td>

<td class="code">
<pre> <span class="comment">//sid 统一为web managment 所在的 frontend server.</span>
<span class="keyword">this</span>.app.rpc.pushserver.pushRemote.add(session, uid,role, <span class="string">'connector-server-client'</span>, uuid, <span class="keyword">function</span>(err, users){
<span class="keyword">if</span>(err){
console.log(err);
<span class="keyword">return</span>;
}

<span class="keyword">if</span>(users){
next(<span class="literal">null</span>, {code: <span class="number">200</span>, msg: <span class="string">'push server is ok.'</span>, users: users});
}<span class="keyword">else</span>{
next(<span class="literal">null</span>,{code: <span class="number">200</span>, msg: <span class="string">"add ok"</span>, users: users});
}
});</pre>
</td>
</tr>

</tbody></table>
</figure>web 管理端调用消息推送

<p></p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3
4
5
6
7
8
9
10
11
12</pre>
</td>

<td class="code">
<pre>Handler.prototype.pushAll = <span class="keyword">function</span>(msg, session, next){
<span class="keyword">var</span> pushMsg = <span class="keyword">this</span>.channelService.getChannel(msg.apikey, <span class="literal">false</span>);
pushMsg.pushMessage(<span class="string">'onMsg'</span>,{msg: msg.msg}, <span class="keyword">function</span>(err){
<span class="keyword">if</span>(err){
console.log(err);
} <span class="keyword">else</span>{
console.log(<span class="string">'push ok'</span>);
next(<span class="literal">null</span>, {code: <span class="number">200</span>, msg: <span class="string">'push is ok.'</span>});
}
});

};</pre>
</td>
</tr>

</tbody></table>
</figure>以上就是主要客户端如何加入到推送队列的代码,以及web 管理端进行消息推送的主要代码,是不是很简单! 完整代码可以参阅我的github <a href="https://github.com/youxiachai"></a><a href="https://github.com/youxiachai">https://github.com/youxiachai</a>

<p></p>

<p><strong>有一点要注意的,如果pomelo 项目要部署到外网或者局域网,frontend 的host 要填写当前host 主机的ip 地址</strong></p>

<p>例如:</p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3</pre>
</td>

<td class="code">
<pre><span class="string">"connector"</span>: [
{<span class="string">"id"</span>: <span class="string">"connector-server-1"</span>, <span class="string">"host"</span>: <span class="string">"127.0.0.1"</span>, <span class="string">"port"</span>: <span class="number">3150</span>, <span class="string">"clientPort"</span>: <span class="number">3010</span>, <span class="string">"frontend"</span>: <span class="literal">true</span>}
]</pre>
</td>
</tr>

</tbody></table>
</figure>部署到某台服务器,需要修改

<p></p>

<p></p>
<figure class="highlight lang-js">

<table><tbody>
<tr>
<td class="gutter">
<pre>1
2
3</pre>
</td>

<td class="code">
<pre><span class="string">"connector"</span>: [
{<span class="string">"id"</span>: <span class="string">"connector-server-1"</span>, <span class="string">"host"</span>: <span class="string">"192.168.1.107"</span>, <span class="string">"port"</span>: <span class="number">3150</span>, <span class="string">"clientPort"</span>: <span class="number">3010</span>, <span class="string">"frontend"</span>: <span class="literal">true</span>}
]</pre>
</td>
</tr>

</tbody></table>
</figure>客户端访问相应的host 的地址.

<p></p>

<p>客户端和服务端的github 地址: <a href="https://github.com/youxiachai/pomelo-pushServer-Demo"></a><a href="https://github.com/youxiachai/pomelo-pushServer-Demo">https://github.com/youxiachai/pomelo-pushServer-Demo</a></p>

<h2 id="menuIndex11">附录</h2>

<p>如果,你现在对pomelo感兴趣的话,你可以看下我写的pomelo 的系列教程(因为还没写好所以暂时只发布在我的博客)暂时一共四篇.基本涵盖了pomelo 大部分基本知识点.</p>

<p><a href="http://blog.gfdsa.net/tags/pomelo/"></a><a href="http://blog.gfdsa.net/tags/pomelo/">http://blog.gfdsa.net/tags/pomelo/</a></p>

<p><strong>广州有招nodejs 程序员(有两年android 开发经验..orz)的吗...能否给个面试机会,联系邮箱: youxiachai@gmail.com</strong></p>

<p>参与的相关社区:</p>

<p>github: <a href="https://github.com/youxiachai"></a><a href="https://github.com/youxiachai">https://github.com/youxiachai</a></p>

<p>cnodejs(Top积分榜 14 ...): <a href="http://cnodejs.org/user/youxiachai"></a><a href="http://cnodejs.org/user/youxiachai">http://cnodejs.org/user/youxiachai</a></p>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  pomelo nodejs