﻿<?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++博客-Sheppard Y-随笔分类-nodejs</title><link>http://www.cppblog.com/yangsf5/category/20809.html</link><description>keep thinking keep coding.</description><language>zh-cn</language><lastBuildDate>Wed, 13 Jul 2016 22:34:57 GMT</lastBuildDate><pubDate>Wed, 13 Jul 2016 22:34:57 GMT</pubDate><ttl>60</ttl><item><title>express的session中间件sessionID问题</title><link>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 28 Feb 2014 07:35:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205993.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205993.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205993.html</trackback:ping><description><![CDATA[<div><div><div></div></div><fieldset><legend><span style="color: #ff0000;">2016-07-12 日更新&nbsp;</span></legend><div><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div></div><a href="http://blog.clawz.me/2014/02/28/14-express-session-id-problem/"><div><span style="color:red;">http://blog.clawz.me/2014/02/28/14-express-session-id-problem/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/02/28/14-express-session-id-problem/"><div></div><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></span></a><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><br />&nbsp; &nbsp; &nbsp;session中间件里的sessionID（以下简称sid）的算法为24byte的全随机。sid重复的可能性比较小，但理论上还是有重复的可能。</span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;session中间件的session维护流程为：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）新session的创建</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）将option里配的sessionStore挂到req上；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）修改res.end函数，在原函数基础上加入req.session.save操作（就是往sessionStore里存session）；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）新session的接入，因为是新session，所以cookie里没有sid信息。随机一个sid，以此sid来创建session，然后将session绑到req上；然后将req和res交给下个中间件或流程处理。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（二）旧session接入</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）同上边的第（1）步；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）同上边的第（2）步；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）cookie里有sid，根据这个sid去sessionStore里取回session信息；如果session过期就取不到session了，就像上边的（3）里那样重新创建一个session。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;为了完全消除sid的重复性带来的影响，就要检查新创建的sid是否已经存在与sessionStore里了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;session中间件的结构在express的以后版本中还会修改，所以我不想动session中间件的源码。于是只能在新session创建后的我自己的逻辑流程中来处理。逻辑流程中，当http包为登陆验证包时，将session中间件给创建的session的sid拿到sessionStore里去查下是否已被使用，如果使用就干掉当前session，并通知当前客户端重试。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;干掉当前session有个技巧，就是直接（req.session=null;）这样即可，因为修改后的res.end里，判断如果req.session未定义，就不会再去调用req.session.save了。当前session是一定不能让他save的，否则就拿当前用户的信息覆盖了之前用此sid的用户，造成那个用户后续逻辑混乱。</div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/205993.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-02-28 15:35 <a href="http://www.cppblog.com/yangsf5/archive/2014/02/28/205993.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>js变量不支持块级作用域</title><link>http://www.cppblog.com/yangsf5/archive/2014/02/19/205854.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 19 Feb 2014 09:00:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/02/19/205854.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205854.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/02/19/205854.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205854.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205854.html</trackback:ping><description><![CDATA[2016-07-12 日更新 
<br />
此篇博客已经迁移到新博客，并做行文检查和优化排版：
<br />
http://blog.clawz.me/2014/02/19/14-js-has-not-block-scope/
<br />
<script src="https://gist.github.com/yangsf5/9088398.js"></script><img src ="http://www.cppblog.com/yangsf5/aggbug/205854.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-02-19 17:00 <a href="http://www.cppblog.com/yangsf5/archive/2014/02/19/205854.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>支持cookie的http客户端agent</title><link>http://www.cppblog.com/yangsf5/archive/2014/02/14/205757.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 14 Feb 2014 03:45:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/02/14/205757.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205757.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/02/14/205757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205757.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205757.html</trackback:ping><description><![CDATA[2016-07-12 日更新 
此篇博客已经迁移到新博客，并做行文检查和优化排版：
http://blog.clawz.me/2014/02/14/14-http-client-agent-with-cookie/
<script src="https://gist.github.com/yangsf5/8994756.js"></script><img src ="http://www.cppblog.com/yangsf5/aggbug/205757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-02-14 11:45 <a href="http://www.cppblog.com/yangsf5/archive/2014/02/14/205757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cookie一小步</title><link>http://www.cppblog.com/yangsf5/archive/2014/01/16/205415.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 16 Jan 2014 03:54:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/01/16/205415.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205415.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/01/16/205415.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205415.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205415.html</trackback:ping><description><![CDATA[<p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"></p><div><div style="orphans: 2; text-align: -webkit-auto; widows: 2;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-11 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/01/16/14-a-step-to-cookie/"><div><div><span style="color:red;">http://blog.clawz.me/2014/01/16/14-a-step-to-cookie/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/01/16/14-a-step-to-cookie/"><div><div></div></div></a><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、怎么纠结上的</span></font></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;近期在准备借鉴云风的skynet来完善我们的架构。这个cookie研究是个插曲。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;我这有个http server只做与数据库的代理接口用，同事那边有个http的web server，他的server需要以http client身份来访问我的server取数据。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;我的server用的express，访问流程为先去一个path验证，验证完，这个http client就可以访问其他path了。验证的时候会标记client对应的session为已验证，之后的每次访问会检查这个标记。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">二、对cookie的认识加深了些</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;这里的cookie流程是这样的，验证之后，server会在response的headers里设置上&#8220;set-cookie&#8221;的值，接下来的request需要带上这个cookie，否则server认为这个client没有被验证。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;第二次request的response里可能会给设置新的cookie，第三次request需要带上第二次respones设置的cookie&#8230;&#8230;</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;这样就是每次访问带上上次返回的cookie，server才会认为你这次的访问启用的client已经被验证过。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;nodejs里的http.request默认是不会捎上cookie的，所以得自己封装下。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">三、ps</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;cookie的wikipedia：<a href="http://en.wikipedia.org/wiki/HTTP_cookie#Implementation">http://en.wikipedia.org/wiki/HTTP_cookie#Implementation</a></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;cookie以前做模拟登陆时有想研究过，那时对http完全不了解，加上其他的事情，给放弃了。这次总算稍微留个感性认识了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;这里写的乱七八糟的，回头有空再完善这篇吧。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><hr /></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;同一个站点的cookie不一定只是登陆够给的那个，而且cookie也不局限于用于登陆标记。例如登陆后浏览好久，开始启用某个功能需要做标记，cookie字段就动态增加了。为此在给node.js的http.request封装的维护cookie的agent后来修改了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;这些内容在《Http权威指南》里将很清楚，经典书才是硬道理。</div></div><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"></p><img src ="http://www.cppblog.com/yangsf5/aggbug/205415.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2014-01-16 11:54 <a href="http://www.cppblog.com/yangsf5/archive/2014/01/16/205415.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo源码分析（3）-pomelo-sync</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 04 Dec 2013 06:28:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204582.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204582.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204582.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/"><div><span style="color:red;">http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/04/13-pomelo-read-source-3/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; 现在分析的版本为0.7版。pomelo-sync，pomelo里用于解决游戏进程中需要持久化的数据在内存与存储系统之间的同步问题。</p> <p>&nbsp;</p> <p>一、pomelo程序如何使用pomelo-sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;新版本的pomelo里增强了支持用户自行扩展的能力。用户只用在app.use(plugin,  opts)就可以了，具体请看pomelo的application.js里的use函数。需要这个plugin里有components成员。use函数里，pomelo将plugin的componets所指的组件load起来，并将opts传给这个plugin的components。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync自身只负责实现db数据与内存数据间的定时同步，所以另一个项目pomelo-sync-plugin就将pomelo-sync封装成了一个componet。app.use(require('pomelo-sync-plugin',  opts)就完成了数据同步插件的装载。</p> <p>&nbsp;</p> <p>二、pomelo-sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync在构造的时候，将参数里的client（与持久化层的链接）、mapping（如各种操作的sql语句的映射表）等赋值给自己的相应成员。最后开启定时刷内存数据到持久化层的计时器SyncTimer。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;对外接口不只在dbsync.js里，还分布在lib/commands下的几个文件里。其中exec/flush/sync等在commands/server.js里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>（一）pomelo-sync.exec</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.exec函数，被用户程序调用。将用户的数据放入pomelo-sync.flushQueue或者pomelo-sync.mergerMap。</p> <p>&nbsp;</p> <p>（二）pomelo-sync.flush</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.flush函数，将单挑数据立即持久化。</p> <p>&nbsp;</p> <p>（二）pomelo-sync.sync</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;pomelo-sync.sync函数，被SyncTimer调用，也可以被用户程序调用，立即将全部内存数据持久化。sync函数里调用的是rewriter.js里的sync。rewriter.sync里将pomelo-sync.flushQueue和pomelo-sync.mergerMap里的数据通过rewrite.tick刷进持久层。rewriter.tick里是通过pomelo-sync.mapping里的映射调对应的sql语句来实现的。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-12-04 14:28 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/04/204582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo0.5.5源码分析（2）-通信</title><link>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 05 Sep 2013 15:09:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203041.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203041.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203041.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/"><div><span style="color:red;">http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/09/05/13-pomelo-read-source-2/"><div></div><p>&nbsp;</p></a><p><br />一、客户端与服务器的通信</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;客户端的通信在pomelo-client里封装了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;服务器与客户端的通信在connector里。底层提供websocket、tcp和socket.io三种方式的通信。</p> <p>（一）connector组件（components/connector.js）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件构造函数里会this.connector从opts里取connector，或者默认为connectors/sioconnector.js。（connector的实现sioconnector和hybridconnector）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的start里会将this.server\this.session\this.connection分别映射到app的对应的组件上。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的afterStart里this.connector.start，并监听this.connector的'connection'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'connection'事件处理为：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将connection关联一个session，监听socket的message事件，接受到message时decode  message，再将message交给server组件的handle，处理完回调里再将返回信息在connector组件的send里处理。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;另外监听session的'bind'事件，处理函数为，调用connection.addLoginedUser。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件里的send，encode  reponse的message，然后交给schedule组件的schedule。</p> <p>&nbsp;</p> <p>（二）hybridconnector的实现</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;connectors/hybridconnector.js以及connectors/hybird。hyrbird实现了原生socket和websocket两种。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;hybridconnector.start里会this.tcpServer=net.createServer，然后把以这个tcpServer为参数创建一个switcher。之后在switcher的'connection'事件里将tcpsocket装进hybridsocket。</p> <p>（1）hybrid/switcher.js</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher构造函数接受一个server参数，并创建this.wsprocessor和this.tcpprocessor。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher监听参数server的'connection'事件，事件处理函数里监听原生socket的'data'事件，判断data是否有http头，如果有，则调用wsprocessor.add，这个add会向外emit  'connection'（事件参数为原生socket），并向socket emit  'data'事件；否则非http，则调用tcpprocessor.add，这个add会以刚才的原生socket为参数创建一个tcpsocket，同时向tcpprocessor  emit 'connection'（事件参数为原生tcpsocket）、向这个原生socket emit 'data'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;switcher也监听了this.wsprocessor和this.tcpprocessor的'connection'事件，处理为向switcher自己emit  'connection'。总结，switcher的职责，将socket的字节流data拼成包，以'message'事件向外emit一个个的完成包msg。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;刚才提到的tcpsocket.js这里处理原生socket的操作。监听了原生socket的'data'、'end'、'error'、'close'事件。例如在'data'处理时，当读入的流长度够一个包的body后就向tcpsocket  emit 'message'。</p> <p>（2）hybridsocket.js</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;将socket和websocket封装为统一接口。构造函数里接受一个id和socket参数。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;hybridsocket监听tcpsocket的'message'事件，将msg  decode，之后处理。例如Package.TYPE_DATA类型的msg，就将这个msg再向hybridsocket自己emit一个'message'事件，其他可能是'handshake'或'heartbeat'事件。</p> <p>&nbsp;</p> <p>（三）server组件</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;官方描述如下&#8220;模块使服务器具备处理客户端请求的能力。该模块主要实现了filter服务，根据当前服务器类型，加载对应handler/目录下的代码，并决定一个请求应该是在当前服务器处理还是应该路由给其他服务器处理。&#8221;，下面看看代码流程。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件的start里初始化filter和handler。</p> <p>&nbsp;</p> <p>二、服务器之间的通信</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>三、框架调用</p> <p>&nbsp;</p> <p>四、session</p> <p>（一）session组件（components/session.js）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;session组件直接用的common/service/sessionService。</p> <p>（二）sessionService</p> <p>（1）Session（object）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session里维护的socket和user信息的之间的对应关系。每个socket有个对应的Session，验证用户身份后就将他们绑定。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session构造函数接受参数socket  id\frontendId\socket\service。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session通过bind\unbind函数将uid绑到this.uid里，并emit  'bind'\'unbind'事件。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session的set\get函数来给Session设取值，由this.settings维护。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Session的send\sendBatch都是直接通过构造时传入的那个socket来操作。</p> <p>（2）MockLocalSession（object）</p> <p>（3）SessionService（object）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;负责对Session的管理。构造函数里将this.sessions和this.uidMap初始为空表。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;SessionService的create负责new  Session，并放到this.sessions里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;bind\unbind函数负责将传入的sid\uid对应绑定到this.sessions\this.uidMap里。uidMap里每个元素是个数组，所以每个uid可以对应多个session？（这个以后再具体了解下）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;sendMessage\sendMessageByUid根据sid\uid往对应的session或sessions发消息。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;其他函数不一一列举了。</p> <p>&nbsp;</p> <p>（三）session的使用</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;看了下chatofpomelo里，是在connector/handler/entryHandler.js里的enter函数，直接用了session.bind。简单用法就是在自己项目的验证uid后自己绑定。</p> <p>&nbsp;</p> <p>五、pomelo-rpc</p> <p>（一）rpc-client</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.create\mailstation.create\mailstation.mailboxFactory挂载mailbox\</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.start(callback)\mailstation.start&amp;callback</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;client.addProxies(remote-calls)\proxy.create\</p> <p>（二）rpc-server</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;lib/rpc-server/server将远程调用处理下，加到opts.services里，然后通过gateway来listen端口和处理message。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203041.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-09-05 23:09 <a href="http://www.cppblog.com/yangsf5/archive/2013/09/05/203041.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pomelo0.5.5源码分析（1）-组件</title><link>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 15 Aug 2013 12:31:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/202563.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/202563.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/202563.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div><a href="http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/"><span style="color:red;">http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/</span></a></div></fieldset><div><a href="http://blog.clawz.me/2013/08/15/13-pomelo-read-source-1/"></a></div><p>&nbsp;</p><p>&nbsp; &nbsp; 由于才接触nodejs几天，看源码时各种细节和设计方法都得熟悉下。结合chatofpomelo-websocket，先从pomelo的使用入口开始看。</p> <p>&nbsp;</p> <p>一、chatofpomelo的开启流程</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Pomelo.createApp出来Application，然后Application.start就开启了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;createApp时会调Application.init来做初始化。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;init里调AppUtil.defaultConfiguration来读入默认配置。例如从master.json里读入master配置（Application.master），从servers.json里读入服务器集群各进程的type、host和port配置（可以通过Application.get("__serverMap__")获取）。</p> <p>&nbsp;</p> <p>二、组件的挂载</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;组件放在components目录下。各组件可以通过Pomelo.components或者直接通过Pomelo来按名取。也可以通过Application.components来按名取（每个组件的名字在自己的name属性里，通常为js文件名加前后双下划线，例如connector.js的组件名为&#8220;__connector__&#8221;）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;下面看下组件的挂载和运行。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Pomelo里会遍历componets目录里的各个js文件，然后require到Pomelo里和Pomelo.components里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.start里先调用AppUtil.loadDefaultComponents，loadDefaultComponents里会根据Application.serverType来Application.load需要的components。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.load里会将Pomelo里的components放到自己的components里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;Application.start/stop/afterStart等方法会统一执行各components里的对应start/stop/afterStart等方法。</p> <p>&nbsp;</p> <p>三、ps</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这篇发表后，在google里搜了下（我的一点恶趣味：经常发表随笔后会看看搜索引擎收录了没）&#8220;pomelo  源码分析  组件&#8221;，发现了pomelo官方wiki里关于组件的说明，奇怪之前准备看组件时没搜到。分析源码之前也浏览了下官方wiki，应该是偏向于了解大概了，各细节没了太大印象。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;不过官方已经有了也没关系，随笔给人参考的价值变小后，就当自己的笔记吧。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外网上也有些pomelo的源码分析了，但是看了眼，跟我想要的不太一样。</p> <p>&nbsp;</p> <p>附官方组件wiki：</p> <ol list-paddingleft-2"=""> <li> <p>Pomelo-Framework里的组件部分：<a href="https://github.com/NetEase/pomelo/wiki/Pomelo-Framework">https://github.com/NetEase/pomelo/wiki/Pomelo-Framework</a></p></li> <li> <p>Pomelo-组件：<a href="https://github.com/NetEase/pomelo/wiki/Pomelo-%E7%BB%84%E4%BB%B6">https://github.com/NetEase/pomelo/wiki/Pomelo-%E7%BB%84%E4%BB%B6</a></p></li></ol><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/202563.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-08-15 20:31 <a href="http://www.cppblog.com/yangsf5/archive/2013/08/15/202563.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>node.js手游服务器调研</title><link>http://www.cppblog.com/yangsf5/archive/2013/08/12/202497.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 12 Aug 2013 09:21:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/08/12/202497.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/202497.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/08/12/202497.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/202497.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/202497.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-08 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/08/12/13-nodejs-mobile-game-server-research/"><div><span style="color:red;">http://blog.clawz.me/2013/08/12/13-nodejs-mobile-game-server-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/08/12/13-nodejs-mobile-game-server-research/"><div></div><p>&nbsp;</p></a><p><br />一、node.js能做啥</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.infoq.com/cn/articles/what-is-nodejs" _href="http://www.infoq.com/cn/articles/what-is-nodejs">http://www.infoq.com/cn/articles/what-is-nodejs</a></p> <p>&nbsp;</p> <p>二、杂项问题</p> <p>1. http的长连接是不是也是只能req/rep模式，能实现服务器端push吗？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;http的长连接即HTTP  keep-alive（HTTP1.1里加入），这个原生的只是为了更少的建立和关闭tcp链接，可以减少网络流量；因为已建立的tcp握手，减少后续请求的延时等。这个http长连接不支持全双工通信。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;http实现&#8220;服务器推&#8221;的技术，一是借助客户端Flash XMLSocket或者Java  Applet套接口来实现；另一种是comet技术。（还有一种遭罪的客户端以一定间隔向服务器发出请求的轮询就不提了）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;comet有两种：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（1）基于AJAX的长轮询（long-polling技术）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2）基于 Iframe 及 htmlfile  的流（streaming）方式</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这两种方式看描述已经离手游服务器差远了，就不去招惹它们了吧。</p> <p>&nbsp;</p> <p>2. 大规模网站的架构？怎么做到水平扩展的？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;网站的需求跟游戏不一样，网站都是http就够了，req/rep即可，没有交互等广播同步之类的复杂状态。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;（pomelo里表示游戏的业务模型很难做到传统网站那种无限水平扩展）</p> <p>&nbsp;</p> <p>3. websocekt是什么？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;html5开始提供的，为了使浏览器和服务器间进行全双工通讯的长链接协议。websocket协议本质上是一个基于TCP的长连接协议。与传统C/S长连接的区别在于，websocket链接开始时的握手协议，客户端首先要向服务器发起一个HTTP骑牛，这个请求和通常的HTTP请求不同，包含了一个附加信息"Upgrade:WebSocket"表明申请协议升级，服务器回应后，即握手完成，websocket链接建立起来，双方自由通信，直到一方关闭链接。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;websocket相对于http的优点，除了全双工通讯，还有服务器与客户端交换的header信息很小。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;websocket与传统socket的区别，前者有帧协议，不需要上层做拼包了。</p> <p>&nbsp;</p> <p>4. redis可以直接搞集群吗？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;数据量太大时，redis的持久化会影响性能，解决方案时用个slave专职做持久化。另外redis容灾和传统web应用的减压，就开多个slave，用于分担读的压力。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;当库到一定数量时，可以用分库分表来水平扩展。&nbsp;</p> <p>&nbsp;</p> <p>5. node.js能用c++扩展吗？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;v8和node都是c++写的。</p> <p>&nbsp;</p> <p>三、网易pomelo能干些啥</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;分布式服务器，方便扩展。另外实现了很多游戏常用模块，如aoi等。</p> <p>&nbsp;</p> <p>四、公司的node.js框架有哪些不能做的</p> <p>1. websocket实现了吗？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;实现中。</p> <p>2. 方便分布式扩展吗？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;貌似没有pomelo那么方便。&nbsp;</p> <p>&nbsp;</p> <p>五、总结</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;node.js做手游服务器的开发还是挺方便的，pomelo已经做很多事情&#8230;&#8230;</p> <p>&nbsp;</p> <p>N、参考</p> <p>1. Comet：基于 HTTP 长连接的&#8220;服务器推&#8221;技术：<a href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/" _href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/">http://www.ibm.com/developerworks/cn/web/wa-lo-comet/</a></p> <p>2. WebSocket：<a href="http://zh.wikipedia.org/wiki/WebSocket" _href="http://zh.wikipedia.org/wiki/WebSocket">http://zh.wikipedia.org/wiki/WebSocket</a></p> <p>3. 使用 HTML5 WebSocket 构建实时 Web 应用：<a href="http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/" _href="http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/">http://www.ibm.com/developerworks/cn/web/1112_huangxa_websocket/</a></p> <p>4. pomelo：<a href="https://github.com/NetEase/pomelo" _href="https://github.com/NetEase/pomelo">https://github.com/NetEase/pomelo</a></p> <p>5. HTTP长连接：<a href="http://www.blogjava.net/xjacker/articles/334709.html" _href="http://www.blogjava.net/xjacker/articles/334709.html">http://www.blogjava.net/xjacker/articles/334709.html</a></p> <p>6. Redis复制与可扩展集群搭建：<a href="http://www.infoq.com/cn/articles/tq-redis-copy-build-scalable-cluster" _href="http://www.infoq.com/cn/articles/tq-redis-copy-build-scalable-cluster">http://www.infoq.com/cn/articles/tq-redis-copy-build-scalable-cluster</a></p><img src ="http://www.cppblog.com/yangsf5/aggbug/202497.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/yangsf5/" target="_blank">Sheppard Y</a> 2013-08-12 17:21 <a href="http://www.cppblog.com/yangsf5/archive/2013/08/12/202497.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>