﻿<?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</title><link>http://www.cppblog.com/yangsf5/</link><description>keep thinking keep coding.</description><language>zh-cn</language><lastBuildDate>Wed, 08 Apr 2026 21:21:05 GMT</lastBuildDate><pubDate>Wed, 08 Apr 2026 21:21:05 GMT</pubDate><ttl>60</ttl><item><title>请访问我博客的新地址-blog.clawz.me</title><link>http://www.cppblog.com/yangsf5/archive/2014/07/09/207593.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 09 Jul 2014 11:58:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/07/09/207593.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/207593.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/07/09/207593.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/207593.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/207593.html</trackback:ping><description><![CDATA[博客搬家，之后就在 <a href="http://blog.clawz.me/">http://blog.clawz.me/</a> 写博客了，这里应该不会再更新。<img src ="http://www.cppblog.com/yangsf5/aggbug/207593.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-07-09 19:58 <a href="http://www.cppblog.com/yangsf5/archive/2014/07/09/207593.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一次简单的hack</title><link>http://www.cppblog.com/yangsf5/archive/2014/05/15/206970.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 15 May 2014 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/05/15/206970.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206970.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/05/15/206970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206970.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206970.html</trackback:ping><description><![CDATA[<div><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/05/15/14-a-easy-hack/"><div><div><span style="color:red;">http://blog.clawz.me/2014/05/15/14-a-easy-hack/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/05/15/14-a-easy-hack/"><div><div></div></div><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"></span></a><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、背景</span></font></span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;朋友公司有款老软件，运行在windows下，C/S架构。客户端为很久前外包开发的。这个客户端为GUI界面。朋友想定时自动让软件做些事情。这个客户端以前设计时没有提供这种定时功能，只有每次执行当次的操作。朋友自己对软件开发不熟，如是找到我。</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;">二、朋友给的解决方案</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&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;">三、我的解决方案</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;这是C/S架构，之前是每次鼠标点击后，客户端给服务器发送相应的网络包。现在要做的是破解这个协议，然后自己写程序定时发送对应协议的网络包即可。</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;">（二）解决方案</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;朋友的解决方案，对于擅长客户端的人是可以的。但是我不怎么擅长，会花不少时间。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&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;">四、解决过程</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;本想找个协议监听软件，我来远程操作就行了，但是他们使用环境公网无法连入。如果我写文档让他来按步骤走，对于非专业人士来说也挺费事的。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;随后我想到他们的行业不那么互联网，他们联系的外包素质应该不是那么高。估计也就是windows那套.net搞的，顶多也就java搞的。所以让他把客户端拷出外网，我来反编译试试。同时我去网上查下.net的反编效果，有网游表示没有混效果的C#代码反编出来跟源代码基本没啥区别，另外以前反编译过java，反编得的代码也跟原工程差不多。所以开始淡定的祈祷反编顺利。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;看了眼客户端里的各文件，感觉到是C#，找了个dotPeek，反编译出来相当清晰。（这玩意的反编译效果比以前反编译flash的代码还清晰，flah反编译后的变量名基本编程local1之流了，这个C#反编出来变量名都是好的）</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;">（二）分析协议</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;C#代码虽没写过，但是语法跟Java/C++非常像。分析起来不是很费劲。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;果然代码写的很windows的.net，客户端直接连接的数据库，然后在客户单发起select之类的查询语句。数据库表和字段名基本是中文拼音首字母。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&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;">（三）实现需求</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;这个是整个过程里最简单的了。用了自己最喜欢的golang写了个没有GUI的程序，定时给他去数据库查想要的数据。</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;">五、后记</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;整个过程的顺利多亏给他们写外包的公司用的C#，还没有做代码混淆之类的。</div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206970.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-05-15 11:11 <a href="http://www.cppblog.com/yangsf5/archive/2014/05/15/206970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>读《Mysql性能调优与架构设计》笔记</title><link>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sun, 04 May 2014 10:38:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206818.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206818.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206818.html</trackback:ping><description><![CDATA[<div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><div><div style="orphans: 2; text-align: -webkit-auto; widows: 2;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/"><div><div><span style="color:red;">http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/05/04/14-note-of-mysql-book/"><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;这几天在review公司项目mysql这块的架构，网上google出来的东西大多是皮毛（特别一些中文站点里的，英文的话阅读和消化都比较慢，除非不得已），有些还明显有些错误。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;之前看《Http权威指南》的甜头还在（加上有些积累现在看技术书速度也快了），所以赶紧找些质量高的mysql方面的书看，找到一本阿里人写的《Mysql性能调优与架构设计》，Fenng也有做序推荐。&nbsp; &nbsp; &nbsp;</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;正文部分为阅读笔记。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">二、硬件关键指标</span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;下边列出是常见性能指标，具体指标的取舍也要看具体应用场景。具体设计时再回头参考书里里讲的例子。<br /><div>1.IO性能高的部件主要由磁盘和内存，各种与IO相关的板卡相关。</div><div>&nbsp; &nbsp; &nbsp;IO性能分为和IOPS（每秒可提供的IO访问次数）和每秒的IO总流量（IO吞吐量）。</div><div>2.CPU（SQL parse和优化），并发高的时候CPU每秒需要处理的请求就高，相应CPU处理能力需要比较强劲。</div><div>3.网络设备</div></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;">二、性能优化</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;书里例子：实时更新一个论坛帖子总量的统计。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;select count(*)语句简单，但是Innodb引擎还是耗时间。而这个需求的强实时更新没多少用户真正关心这个。定时更新可提高很大的性能。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&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;">（1）有几类数据不适合存到数据库中：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;1.二进制多媒体数据（图片、音频、视频等），这类数据对数据库空间资源耗费非常严重，且这些数据的数据存储很消耗数据库主机的CPU资源。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;2.流水队列数据，支持事务的存储引擎为了事务安全性和可恢复性，需要记录所有变更的日志信息，而流水队列数据会不断的被INSERT\UPDATE\DELETE，导致日志量很大。使用成熟的第三方队列软件处理，性能将会成倍提升。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;3.超大文本数据，从5.0.3开始，VARCHAR，实际数据小于255字节时，实际存储空间和实际数据长度一样，可一旦长度超过255字节之后，所占用存储空间是实际数据长度的两倍。不光性能低下，还是浪费空间。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）是否合理利用了应用层的cache。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）数据层的存取实现都是最精简的吗。在程序里不要过度依赖面向对象思想。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）过度依赖数据库SQL语句的功能造成数据库操作效率低下。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;尽量减少与mysql的交互次数和SQL复杂度。不要对可扩展性过度追求，导致系统设计时开分太李三，导致需要大量Join语句。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）重复执行相同的SQL造成资源浪费。</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;">（四）硬件设施理性化</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;">三、合理利用锁机制来优化mysql</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;">四、Query优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;主要优化思路和原则：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）优化更需要优化的Query。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）定位优化对象的性能瓶颈。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）明确的优化目标。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）从explain入手。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）多使用profile。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（6）永远用小结果集驱动大的结果集。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（7）尽可能在索引中完成排序。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（8）只取出自己需要的columns。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（9）仅仅使用最有效的过滤条件。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（10）尽可能避免复杂的join和子查询。</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;">五、Schema设计的性能优化</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;">（1）不一定要追求范式</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）适度冗余&#8212;&#8212;让query尽量减少join。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）大字段垂直分拆</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;字段特别大，访问频率又很低的字段拆出去。因为记录存储是一条一条的存放，查询某些数据时，也会读取到这个访问不高的大字段，比较浪费IO资源。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）大表水平分拆&#8212;&#8212;基于类型的分拆优化</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;把少量访问频率极高的记录水平拆分出去。例如论坛里的置顶帖子从普通讨论贴里分拆出去为单独的表。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（5）统计表&#8212;&#8212;准实时优化</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;选择更小的数据类型，可以降低IO消耗。另外不同数据类型的CPU处理方式也不一样。例如通过整数类型代替浮点数或者字符类型。</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;这条对性能没啥影响，但是对数据库的维护影响非常大。库的字段越来越多&#8230;&#8230;</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;">六、mysql server性能优化</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;">七、存储引擎优化</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;">八、架构设计</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;">（二）mysql replication</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;水平切分和垂直切分，之前项目里做架构时已基本了解。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（四）cache和search的利用</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;cache就是memcache之类的。search主要用来做全文检索。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（五）mysql cluster</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;">（七）高可用设计之mysql监控</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;"></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><hr /> &nbsp; &nbsp; &nbsp;看完上边后又在看《高性能mysql》第三版2013年初版的，美国人写的，这本是mysql的经典之作，比上边那本更好吧。就是内容详细，啥都有。详细的基准测试方法、特性细节（原理）、架构考虑，这几年mysql升级的特性（如分区等），讲述的mysql版本已经新到5.5~稍许5.6前瞻。还有作者都是相关经验很多年的大拿。内容写的也不枯燥，很向那些编程方面的经典书的书写风格。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;时间宝贵，推荐看《高性能mysql》这本就行了。</div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206818.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-05-04 18:38 <a href="http://www.cppblog.com/yangsf5/archive/2014/05/04/206818.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Docker应用调研</title><link>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sat, 26 Apr 2014 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206724.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206724.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206724.html</trackback:ping><description><![CDATA[<div><div></div><fieldset><legend><span style="color: #ff0000;">2016-07-12 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/04/26/14-docker-usage-research/"><div><span style="color:red;">http://blog.clawz.me/2014/04/26/14-docker-usage-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/04/26/14-docker-usage-research/"><div></div></a><br />&nbsp;一、背景 <div>&nbsp; &nbsp; &nbsp;项目里编译打包客户端程序时经常出现问题，有环境不一致问题或者代码冲突问题。</div><div>&nbsp; &nbsp; &nbsp;之前了解过<a href="https://www.docker.io/">docker</a>可以应用环境作为一个一体化的服务来使用，所以想看看docker是否能给我们客户端同学提供些方便。</div><div></div><div>二、主要关注点</div><div>（一）docker能运行在哪些操作系统，mac、linux、windows？</div><div>&nbsp; &nbsp; &nbsp;都可以，docker现在release到0.10.0版了，还没到1.0的正式版。官方不推荐将当前的docker运用在生产环境中。</div><div>&nbsp; &nbsp; &nbsp;docker内部开发是在ubuntu上进行了，所以ubuntu上支持最好。mac和windows这些的docker运行方式，现在是在操作系统上装虚拟机（如VirtualBox），再在虚拟机里运行使用docker。</div><div></div><div>（二）docker容器里能运行什么环境，mac、linux、windows？</div><div>&nbsp; &nbsp; &nbsp;docker里能运行的系统称为image，目前image大多是linux。这也挺正常的，mac os x和windows都是商业收费的，怎么可能随便让搭建image。</div><div>&nbsp; &nbsp; &nbsp;所以我想用docker来服务我们客户端环境搭建的话，image的事情还得自己搞下。</div><div></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206724.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-04-26 16:05 <a href="http://www.cppblog.com/yangsf5/archive/2014/04/26/206724.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>控制反转</title><link>http://www.cppblog.com/yangsf5/archive/2014/04/14/206573.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 14 Apr 2014 03:10:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/04/14/206573.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206573.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/04/14/206573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206573.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206573.html</trackback:ping><description><![CDATA[<div><div style="orphans: 2; text-align: -webkit-auto; widows: 2;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/04/14/14-ioc/"><div><span style="color:red;">http://blog.clawz.me/2014/04/14/14-ioc/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/04/14/14-ioc/"><div></div></a><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、概念</span></font></div><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;从酷客看的</span><a href="http://coolshell.cn/articles/6950.html" style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">《需求变化与IoC》</a><span style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">，里边讲的东西挺形象的。</span><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;用户需求是一直变的，如果一直根据用户来做，程序员会累死。</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;控制反转的比较形象的例子：PC机的架构都是设计好的，用户想要什么样的，再去组装配置。而不是用户说想要什么功能，每个用户去设计一套PC架构，这样厂商就会累死，而且成本非常高。</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;">二、拓展</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;不被多变的需求牵制，做好自己的人生架构设计。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;不因为某某小事而去花大精力去钻研没用的东西，要专注自己喜欢的技能。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;还没仔细想玩。</div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206573.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-04-14 11:10 <a href="http://www.cppblog.com/yangsf5/archive/2014/04/14/206573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>claw设计草稿</title><link>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 31 Mar 2014 03:09:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/206404.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/206404.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/206404.html</trackback:ping><description><![CDATA[<div><div><div><div></div><fieldset><legend><span style="color: #ff0000; line-height: normal;">2016-07-12 日更新&nbsp;</span></legend><div><span style="line-height:normal;color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：<br /></span><div></div></div><a href="http://blog.clawz.me/2014/03/31/14-claw-design/"><div><div><span style="color:red;">http://blog.clawz.me/2014/03/31/14-claw-design/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2014/03/31/14-claw-design/"><div><div></div></div><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"></span></a><span style="orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><font face="微软雅黑" size="3"><span style="line-height: normal;">一、目标</span></font></span><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;参考云风skynet，实现go版本的开源服务器引擎。</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;">二、细节</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;按服务来拆模块的好处不说了。只说go来的实现方式。go里有channel和goroutine。消息队列和轻量级线程都天然解决了。</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;">（二）服务间的通信</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;同进程内的服务之间通信，直接往对方channel发消息即可。不同进程里靠各进程自己的harbor服务来转发。harbor服务来负责集群间的通信。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;集群里设置一个master服务来做全局的名字服务，主要用于登记和同步集群里各个进程开启的各个服务。所有harbor启动后向master注册自己，master向所有harbor广播同步新加入的这个机器。</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;">（三）组播</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;经常需要向某几个服务广播一个消息，组播问题。multicast服务来管理组播。</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;">（四）日志</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;使用glog。</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;">三、已实现的服务</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（一）master和harbor</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;暂时master做为harbor的中心控制器的。后续会改进，做成harbor之间两两通信，减少对master的单点依赖。</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;">（二）gate</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;gate用来做通常的网络监听用。目前的很简单，用户需要向这个服务器注册自己的包解析和处理器。</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;">（三）web</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;web负责http的监听，template的加载cache，几个通用函数的提取。</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;项目地址：<a href="https://github.com/yangsf5/claw">https://github.com/yangsf5/claw</a></div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"><a href="https://github.com/yangsf5/claw"></a></div></div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;"></div></div><img src ="http://www.cppblog.com/yangsf5/aggbug/206404.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-03-31 11:09 <a href="http://www.cppblog.com/yangsf5/archive/2014/03/31/206404.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><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>了解云风的skynet</title><link>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 16 Jan 2014 03:25:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205413.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205413.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205413.html</trackback:ping><description><![CDATA[<div></div><fieldset><legend><span style="color: #ff0000;">2016-07-11 日更新&nbsp;</span></legend><div style="display:inline-block;"><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/"><div><span style="color:red;">http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/01/16/14-cloudwu-skynet-research/"><div></div><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"></p></a><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><br />（PS开始应用《暗时间》里提到的理论，将skynet用自己的话来总结并写下来，这样能充分思考并转述为自己的记忆线索）</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">一、skynet设计的理解</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（一）单个skynet节点</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（1）愿景</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;充分利用多核。最初想法是多进程。像咱们nodejs里多核就只能是多进程了，因为每个nodejs进程是单线程的。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;多进程是遵循unix设计哲学，工具链形式，分拆进程的形式来分拆模块，减少复杂度和耦合性，方便编程及维护。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;后来云风他们发现lua做为嵌入式脚本，写逻辑时很好用的，反正如何都要用lua，而且lua提供了沙盒，这样多进程可以变为单进程多个沙盒，这样综合了多进程和单进程多线程的优势。多线程里共享资源，在同一进程地址空间，访问更高效。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（2）核心功能（门房？）</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;很精简，仅解决一个问题。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet里不实现具体游戏逻辑，后者些放到一个一个动态库里（so文件）。skynet将这些so注册到自己里边，每个so一个永不重复的id，类似于数据库的autoincreament。看描述这个id是skynet自己运行时当次维护的，而不是模块配置好终身的id。模块的永久有效唯一标示为名字，skynet提供了名字服务，可以给每个模块取一个易读的名字。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（3）核心不解决什么问题</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet主张所有服务在同一OS进程协作完成。核心里就没管跨机通讯，单个服务的崩溃和重启也没管，云风表示这些应该由上层处理，他有责任暴露错误，而不是隐藏。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;这个设计的原因，游戏和操作系统不一样，操作系统默认不信任任何进程，各进程崩溃什么的不应影响其他进程，所以某个进程挂了，他就安葬它，而其他进程美好的生活。单游戏是为玩家服务的，某个环节出错都有可能造成玩家利益混乱，所以那里错了就整个流程（服务器）挂掉吧。没有必要让出错模块被隔离开，而其他模块却继续提供服务导出未预知行为。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;上边说的东西应该上层考虑，使用lua的沙盒就能做策略隔离。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（4）skynet运行时逻辑流</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet负责且只负责将一个数据包从一个服务发送到同一进程的另一个服务里。发送服务直接调发送API，skynet收到数据包后，调用接受者服务的注册的callback，即发给了接受者服务。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet保证在各模块初始化时、每个独立的callback调用时，都是相互线程安全的。这样编写服务的人就不需要考虑多线程的任何问题了，只需专心处理给他的一个个数据包。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;PS：天龙的场景lua有点像这里的单个服务。不知天龙的跨线程切场景情况在这里也可以给简化为单线程？（回头看源码再研究这个问题）<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（5）消息调度</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">TODO</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（6）gate和connection</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">TODO</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&#8203;<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（二）skynet集群</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;集群里最多支持255个skynet节点，每个skynet节点有一个id，成为harbor id。这个id是集群层面指定，可以人为分配，也可以由一个中央服务器协调分配。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（1）集群间通信</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;skynet核心层纸负责在往外发消息时在source字段上加上自己的harbor id。而集群间的通信，是由单独的harbor服务来做的。skynet将是往集群其他节点发的消息，就转发到harbor内。harbor会跟集群内跟自己结识的skynet的harbor简历tcp链接。harbor把消息发给目标harbor。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;harbor间的通信为单向的tcp管道。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;master服务来同步全局的名字服务。每个skynet都会知道其他节点上装配了哪些服务，好路由过去。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">（2）组播</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;TODO</p><img src ="http://www.cppblog.com/yangsf5/aggbug/205413.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:25 <a href="http://www.cppblog.com/yangsf5/archive/2014/01/16/205413.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>http与socket验证的区别</title><link>http://www.cppblog.com/yangsf5/archive/2014/01/10/205271.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 10 Jan 2014 05:53:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2014/01/10/205271.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/205271.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2014/01/10/205271.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/205271.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/205271.html</trackback:ping><description><![CDATA[<div style="orphans: 2; widows: 2;"><font face="微软雅黑"></font></div><fieldset><legend><span style="color: #ff0000; font-family: 微软雅黑; line-height: normal; orphans: 2; widows: 2;">2016-07-11 日更新&nbsp;</span></legend><div style="orphans:2;widows:2;line-height:normal;"><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2014/01/10/14-http-socket-auth-diff/"><div><span style="color:red;">http://blog.clawz.me/2014/01/10/14-http-socket-auth-diff/</span></div></a></fieldset><a href="http://blog.clawz.me/2014/01/10/14-http-socket-auth-diff/"><div></div><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"></p></a><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /><br />&nbsp; &nbsp; 这是很基础的概念，之前没怎么弄过http。对于自己，算是做个笔记吧。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">一、socket安全验证</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;socket链接是握手之后就一直连着，所以这条链接在第一包验证之后，之后这条链接不需要再验证。&#8220;第一个包&#8221;可能描述不准确，因为有时候第一包不一定就验证，可能是做路由之类。这里就不管这种情况了，只管第一个包直接验证的情况。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;可以理解为server接受到client的链接，并且验证通过（如用户及密码对了）这个client链接后。以后这个client发过来的包，server都直接做逻辑处理而不再需要做验证链接合法性。这个信任是直到链接断开的。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp; &nbsp; 如果非法客户端来模拟登陆，至少需要得到有效的id及密码，这已经是密码自身安全的事情，不涉及这里谈的链接安全性。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;如果非法客户端用正确的id及密码登陆后，发些非法包，这里的包验证应该是服务器上包处理时的包检查及逻辑检查的事，就是通常的游戏说的防刷（包频率、包里数据的合法范围等）。</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;"><br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">二、http的安全验证</p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;这里只关心http的短连接。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;短连接就是每次建立链接-发包-断开。同一client的前后两次发到server的包，也相当于独立的两次，同一client的验证就需要每个http请求都要验证下。于是有了session和cookie。cookie是将client的标识放在client端，常用于server没有账户密码验证的方式。这里不讨论cookie。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;server在第一个http请求验证client后，给他分配一个session。这个session简单的可以理解为server和client约定的一个client凭证（有有效期）。之后client在每个请求里加上这个session里规定的值，例如一个合适长度的随机字符串。<br /></p><p style="margin-right: 0px; margin-left: 0px; font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">&nbsp;&nbsp;&nbsp;&nbsp;这里的session不能有让恶意用户很容易破解的规律，例如用户的id之类的。所以上边提到随机字符串之类的。&nbsp; &nbsp;&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/205271.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-10 13:53 <a href="http://www.cppblog.com/yangsf5/archive/2014/01/10/205271.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集群实现细节（5）-登陆流程修改</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/16/204821.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 16 Dec 2013 02:44:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/16/204821.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204821.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/16/204821.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204821.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204821.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/16/13-game-cluster-design-detail-5/"><div><span style="color:red;">http://blog.clawz.me/2013/12/16/13-game-cluster-design-detail-5/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/16/13-game-cluster-design-detail-5/"><div></div><p>&nbsp;</p></a><p><br /><br />一、回顾</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;之前的登陆流程在<a title="" href="http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html" target="_self" _href="http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html" data_ue_src="http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html">这篇里</a>。之前的登陆流程简述：</p> <p>（1）先检查是否同服已登陆，是则两个链接都踢掉，否则进入下步；</p> <p>（2）判断是否异服已登陆，是则告诉异服踢老链接，随后踢自己这的新链接。否则进入下步；</p> <p>（3）当前服务器登陆相关流程走完后，向玩家在线列表汇报（写入这个玩家登陆的服务器id为我）。这时的汇报写入为redis的CAS操作，为了检查是否发生了那篇里介绍的同账号瞬间多起登陆事件。CAS操作成功，本服链接登陆完成，做后续操作。否则CAS操作失败，表示瞬时登陆的异服同账号的另一个链接的登陆流程走的快，已经完成整个流程，包括汇报进在线列表。这时的处理只用将慢拍的本服链接关闭就行了。</p> <p>&nbsp;</p> <p>二、存储架构变为redis+mysql后的问题</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;现在玩家上线时需要从mysql加载玩家离线数据到redis，需要考虑这个数据加载放到上边登陆流程哪一步里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;首先数据加载有可能会失败，如果数据加载出问题，就不能让该玩家登陆。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果放到（2）（3）之间，就是redis的CAS之前，这样瞬间同一账号多起登陆都有可能开始进行加载数据步骤，而处理的快的那个客户端就有可能汇报登陆完成之后立即玩游戏并更新了自己在redis里的数据，处理的慢的客户端还这时还在将mysql的数据往redis的加载，会覆盖快的客户端更新的数据。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果放到（3）里redis的CAS之后，数据加载失败，就需要回退CAS的操作。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;可见第二种至少可以保证数据正确性。这种情况抽象下，就是第一种里没有提供事务操作的回滚（慢客户端覆盖数据后发现干了坏事却不方便回滚自己的破坏）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;（2）这个操作当时是为了区分异服登陆并玩游戏很久了和瞬间多起登陆这两种情况的。现在想想这两种情况的处理统一为直接踢掉新旧两个链接也没什么，毕竟瞬时登陆的情况不多。</p> <p>&nbsp;</p> <p>三、新流程</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;根据上边的结论，新的流程为：</p> <p>（1）先检查是否同服已登陆，是则两个链接都踢掉，否则进入下步；</p> <p>（2）向玩家在线列表CAS报告自己登陆。如果失败告诉异服踢掉该账号老链接，自己这边踢掉该账号新链接即可。成功则进入下步；</p> <p>（3）加载数据，成功就进入正常游戏流程。加载失败，就去在线列表里清掉自己。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204821.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-16 10:44 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/16/204821.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集群实现细节（4）-冷热数据划分及同步</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/13/204771.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 13 Dec 2013 07:58:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/13/204771.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204771.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/13/204771.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204771.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204771.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/13/13-game-cluster-design-detail-4/"><div><span style="color:red;">http://blog.clawz.me/2013/12/13/13-game-cluster-design-detail-4/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/13/13-game-cluster-design-detail-4/"><div></div><p>&nbsp;</p></a><p><br />&nbsp;</p><div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">一、玩家数据在redis与mysql之间的同步</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;由于redis操作可以保证多个进程读写同一个玩家数据时的原子性。所以之前多个逻辑服务器读写同一玩家数据时没有什么问题，但是现在redis和mysql之间需要同步玩家的数据（例如定时将redis里的在线玩家数据刷进mysql里做持久化）。这个同步的逻辑代码放哪呢？</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;观察需求特性，玩家上线加载到redis做cache、定时更新持久层、玩家离线时清掉cache并更新到持久层，都是redis和mysql之间的数据交互。这些可以放到一个服务里，单进程实现，或者集成到现在的逻辑服务器里。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;方便实现，做下限制。玩家登陆的逻辑服务器记为他的owner服务器，每个玩家数据的redis/mysql同步只由他owner来做。&nbsp;这样问题就简化了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;这里有些做法是突然想到的，就像《暗时间》里提到的联想式的，而不是归纳演绎的。最近在看《暗时间》，好书，里边就提到边写边思考，思考时&#8220;大脑内存&#8221;有上限的，边写就能把部分思考分支换出笔记这种&#8220;硬盘&#8221;上，然后大脑专心思考其中一两个分支，想的差不多，再回过头将&#8220;笔记硬盘&#8221;上的数据换入&#8220;大脑内存&#8221;&#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;如果逻辑服务器宕机，它上边的玩家就掉线了，而这台逻辑服务器是不能对这些玩家做离线数据持久化的。这种情况需要进一步思考TODO。另外之前这种玩家怎么标记为离线，需要再想一遍，也TODO了。</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;">二、从本质出发review我们的存储架构</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;">&nbsp;&nbsp;&nbsp;&nbsp;本质我们的架构是为实现游戏的玩法目标来做的，另一方面我们考虑开发成本、维护成本、机器成本。好的架构是权衡目标实现程度和这些成本的耗费。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;目标是实现同一国家的玩家不分区分服。之前缓存和持久化都是用redis来做，开发成本和维护成本都挺低的。但是需要很多机器。现在控制机器成本，所以需要分析我们数据的特点，将冷数据放到mysql这种机器需求量少的数据库。具体到表的分析这里就不方便贴了。说下大概分类：</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）离线玩家的冷数据，离线玩家的私人数据，不需也不能与别人交互的；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）离线玩家的热数据，例如名字，好友是想看到离线好友的名字的；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（3）在线玩家的一直更新的数据，例如经验值，游戏货币等；</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（4）在线玩家的到强实时玩法时才更新的数据。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;（1）里的数据无疑问放在mysql里。（2）里的数据还得根据情况看是否一致放在redis里，即离线的玩家这部分数据也放在redis里。（3）里的数据无疑问在线是放到redis里。（4）里的数据可以根据情况考虑下延迟加载什么的，即玩家上线时这部分数据不马上加载到redis，而是等玩家开始这个玩法时才从mysql里加载到redis里。这个需要考虑这个玩法的数据量以及是否玩家参与度高。</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;">三、扩展</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;先了解mysql单表数据上限、然后mysql单库上限。这里的上限指不影响效率的上限，而不是物理上限。拿到上限数据后，做预分库分表。分库分表也要好好想想。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;查了下，mysql 5.1里InnoDB引擎表空间最大容量为64TB。在查我们公司服务器配置表里硬盘，最低有100G的，最高600多G的。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;初步确定mysql的sharding和partition为这样：不同物理机之间的sharding为分个大的id段，单个物理机上即单库内的如果表还是很大就做自己的partition。最终看上线怎么定，再定这个跨机sharding的id段长度，至于单机的partition，对代码来说是不需要管的，运维根据性能搞就行了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;先简单算下，每人100k，500w人一个sharding，需要大约500G空间。</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;">四、其他架构展望</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><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204771.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-13 15:58 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/13/204771.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集群实现细节（3）-DB集群</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/06/204628.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 06 Dec 2013 08:53:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/06/204628.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204628.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/06/204628.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204628.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204628.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/06/13-game-cluster-design-detail-3/"><div><span style="color:red;">http://blog.clawz.me/2013/12/06/13-game-cluster-design-detail-3/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/06/13-game-cluster-design-detail-3/"><div></div><p>&nbsp;</p></a><p>&nbsp;</p><p>一、纯redis集群</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果redis不止做cache，也做持久化，那就得好好算算我们的业务规模需要多少台机器来支撑。1000w注册玩家，每台机器16G内存（为了保证效率取3/4为可用，即12G）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果每个玩家1M数据，总约9765G，不算热备，需要814台机器。每台机器存储1.2w人。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果每个玩家16k数据，总约153G，不算热备，需要13台机器。每台机器存储77w人。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果每个玩家1k数据总约9.5G，不算热备，需要1台机器。每台机器存储1000w人。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;注册玩家会越来越多的&#8230;&#8230;</p> <p>&nbsp;</p> <p>二、mysql做持久化，redis做cache</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;只说存储，一个mysql支持几T数据没什么问题。例如上边1000w注册玩家，每个玩家1M数据，总数据近9.5T，存一个mysql足够。但是如果高峰在线玩家并发到100w，需要将大部分操作规划到redis这个cache上。否则mysql仍然因磁盘IO太多吃不消。</p> <p>&nbsp;</p> <p>（一）与纯redis集群相比的劣势</p> <p>（1）好友需要看离线玩家的信息，而离线玩家在mysql里，如果频繁？</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;把离线玩家可能被别人查看的信息不存mysql了，改用redis做持久化。</p> <p>（2）GM工具改玩家消息，需要改mysql和redis的cache里。会不会容易出问题？</p> <p>&nbsp;</p> <p>（二）优势</p> <p>（1）redis只做cache集群了，用twemproxy管理就行了。如果redis做持久化，还是需要自己来分片，且早期就要规划好。</p> <p>（2）单个玩家的数据涨到1M的时候，总用户涨到2000w~3000w，再加两个mysql。</p> <p>&nbsp;</p> <p>三、redis做cache+热数据持久化，mysql做冷数据持久化</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这里其实就是将二里边的每个玩家的部分很热的数据从mysql移到redis里做持久化。但是玩家在线时，他的数据基本都算是热的。所以这个方案不是很好设计。</p> <p>&nbsp;</p> <p>&nbsp;</p> <p>最后、参考</p> <p>1. redis官方关于分片的文章：<a href="http://redis.io/topics/partitioning" _href="http://redis.io/topics/partitioning">http://redis.io/topics/partitioning</a></p> <p>2. twemproxy文章：<a href="http://antirez.com/news/44" _href="http://antirez.com/news/44">http://antirez.com/news/44</a></p> <p>&nbsp;</p><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204628.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-06 16:53 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/06/204628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>了解MongoDB</title><link>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 05 Dec 2013 11:07:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204608.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204608.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204608.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/05/13-mongodb-research/"><div><span style="color:red;">http://blog.clawz.me/2013/12/05/13-mongodb-research/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/12/05/13-mongodb-research/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; &#8203;MongoDB为k-v数据库，他们存储方式为BSON，操作接口基本都是JSON，查询，搜索都很方便。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;例如mysql里一个表，id和data，data为这条记录的数据，数据为了扩展，例如不同的记录的data可能包含很多字段，且字段不一定相同，以后也会有不少类型的字段。这时我把这些不确定的字段encode成一个xml或者json或者protobuf之类的数据流存到data里。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这么做记录的具体数据关联的详细数据扩展很灵活了。但是想搜索data里的各字段时，在mysql数据库里就不那么方便了，基本要遍历。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这个时候将这个data备份一份到MongoDB里，就很方便了。MongoDB里的每条记录为一个key-value，value即存储我们上边的data。这时我们取data里的字段做条件查询是MongoDB直接支持的。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外MongoDB支持自动切热备，自动分片等高级功能&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;但是另一方面，这个东西出来的不久，现在还不敢将他作为持久化的DB。上边的例子是mysql里有份数据为生产环境的依赖数据，备份到MongoDB的数据只是为了查询。MongoDB里数据出问题是没关系的。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204608.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-05 19:07 <a href="http://www.cppblog.com/yangsf5/archive/2013/12/05/204608.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>软硬件工具诡异事件集锦</title><link>http://www.cppblog.com/yangsf5/archive/2013/11/26/204447.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Tue, 26 Nov 2013 01:58:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/11/26/204447.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204447.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/11/26/204447.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204447.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204447.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><p><a href="http://blog.clawz.me/2013/11/26/13-few-tool-debug/"><span style="color:red;">http://blog.clawz.me/2013/11/26/13-few-tool-debug/</span></a></p></fieldset><p><a href="http://blog.clawz.me/2013/11/26/13-few-tool-debug/"><br /></a><br /></p><div><p style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; margin-right: 0px; margin-left: 0px;"></p><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;">（1）win7的任务栏的自动隐藏偶尔会失效</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;工作机器上，不想被IM、邮件等随时干扰，将win7上的任务栏设置了自动隐藏，集中工作结束才集中处理IM和邮件等消息。</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;">&nbsp;&nbsp;&nbsp;&nbsp;自己想到右边的托盘图标有消息的时候会临时弹出任务栏。想想试试来个托盘消息，刚好我的AKG耳机插入的音频孔的时候会弹喇叭，拔插下耳机，点掉那个喇叭图标，任务栏再次隐藏了。搞定。</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;">二、软件</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（1）tmux的pane切来切去会吃掉一列字符</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;解决：将tmux从1.6升级到1.8就不会了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">（2）chrome里登录github.com一直不成功</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;问题描述：工作机chrome里从github.com logout后，再次登录时一直重定向到首页，开启隐身模式是可以的。家里机器上普通模式的chrome都logout/login没问题。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;解决：最开始以为是github官网挂了，隐身模式能登就否定了这个猜测。之后以为是系统装了什么东西，等重新启动后还是不行。如是ctrl+shift+j打开控制台看了下http的返回，response里表示session not found。应该是cookie错乱，清了github的cookie，再一登就OK了。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;感想：NND，作为了一个程序员好不专业，早应该开控制台来debug了。debug还没深入骨髓。</div></div></div><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204447.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-11-26 09:58 <a href="http://www.cppblog.com/yangsf5/archive/2013/11/26/204447.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>天龙商店玫瑰与经济稳定</title><link>http://www.cppblog.com/yangsf5/archive/2013/11/22/204382.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 22 Nov 2013 07:08:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/11/22/204382.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204382.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/11/22/204382.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204382.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204382.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/11/22/13-tian-long-ba-bu-mei-gui/"><div><span style="color:red;">http://blog.clawz.me/2013/11/22/13-tian-long-ba-bu-mei-gui/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/11/22/13-tian-long-ba-bu-mei-gui/"><div></div><p>&nbsp;</p></a><p><br /><br />&nbsp; &nbsp; 几年前在天龙时，让我很感叹的策划案是，商城的玫瑰道具，玩家可以花元宝买，然后再把玫瑰扔商店得金币，这样维护游戏内的经济稳定。今天又跟现在公司的同事提到这个，为了思路清晰点，再以博客的形式来边仔细想想。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果游戏内没有元宝兑换金币的官方途径，玩家最便捷的获取金币的方式，是充值获得元宝，然后拿元宝去找别的玩家交易换取金币。金币的供应量会影响元宝与金币兑换比例。假设元宝与金币兑换比例的正常平均值为100:50，当服务器内金币流动量很小时，例如新服时，兑换比例为100:30；而突然涌入很多刷金工作室，金币供应量变很大，兑换比例变为100:100，这时金币贬值。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;玩家简单分为两种，RMB玩家和非RMB玩家。RMB玩家的需求是，自己的RMB换的元宝买的金币能实现自己的一些装备之类的大提升，就是购买力要强。非RMB玩家（这里指不用外挂，不利用游戏漏洞，正常打金币的玩家）的需求是，自己辛苦赚的金币能多换些元宝。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;当刷金工作室进入游戏后，金币的产生变大了。如果工作室的金币都供应流动起来，金币就贬值了。非RMB玩家利益严重受损，产生挫败感。如果工作室垄断金币市场，金币甚至升值，RMB玩家利益受损。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这里讨论在打击外挂和打击工作室之外的手段来稳定经济系统。金币流动量突然变大，系统方面可能考虑的是金币的掉落和任务奖励的调低等。反之变少时，提高掉落和任务奖励。或者另一个途径调整道具的价格。这都挺麻烦的。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;现在可以通过玫瑰道具的买卖，来间接进行元宝与金币互兑的后。游戏内玩家间交易的金币升值，要兑换金币的玩家就选择去元宝商店兑换金币。使交易的汇率比商店的稍低。这保证了金币的价格不会高过设定值，从而保证了RMB玩家的利益。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果交易的金币贬值了呢？也可以说元宝升值了呢？非RMB玩家需要花更多的钱买同样的元宝。貌似玫瑰花这个道具对这种情况没有什么抑制作用。那到这里的结论是，玫瑰道具只是抑制了金币升值/元宝贬值这个单方面的经济失衡问题。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;（暂时只想这么多，以后有空再补充）</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204382.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-11-22 15:08 <a href="http://www.cppblog.com/yangsf5/archive/2013/11/22/204382.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>top里显示的cpu百分比计算方式</title><link>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 07 Nov 2013 11:20:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204148.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204148.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204148.html</trackback:ping><description><![CDATA[<pre style="font-family: Consolas, 'Liberation Mono', Courier, monospace; font-size: 12px; margin-top: 0px; margin-bottom: 0px; color: #333333; line-height: 17.99715805053711px;"><div id="LC1" style="padding-left: 10px;"><div></div><fieldset><legend><span style="color: #ff0000; line-height: 17.9972px;">2016-07-11 日更新</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span><br /><div></div></div><a href="http://blog.clawz.me/2013/11/07/13-top-source/"><div><div><span style="color:red;">http://blog.clawz.me/2013/11/07/13-top-source/</span></div></div></a></fieldset><a href="http://blog.clawz.me/2013/11/07/13-top-source/"><div><div></div></div></a><br /><br />&nbsp;top看到的cpu信息解释的不是很清晰，就看下源码怎么写的吧。</div><div id="LC2" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序很简单，基本都在top.c里。</div><div id="LC3" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;load里的cpu详细信息代码如下：</div><div id="LC4" style="padding-left: 10px;"></div><div id="LC5" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #000000; ">smpcpu&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpus_refresh(smpcpu);<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(CHKw(Curwin,&nbsp;View_CPUSUM))&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;display&nbsp;just&nbsp;the&nbsp;1st&nbsp;/proc/stat&nbsp;line</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">smpcpu[Cpu_tot],&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Cpu(s):</span><span style="color: #000000; ">"</span><span style="color: #000000; ">);<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">}&nbsp;</span><span style="color: #0000FF; ">else</span><span style="color: #000000; ">&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">int</span><span style="color: #000000; ">&nbsp;i;<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">char</span><span style="color: #000000; ">&nbsp;tmp[SMLBUFSIZ];<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;display&nbsp;each&nbsp;cpu's&nbsp;states&nbsp;separately</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">for</span><span style="color: #000000; ">&nbsp;(i&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">0</span><span style="color: #000000; ">;&nbsp;i&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;Cpu_tot;&nbsp;i</span><span style="color: #000000; ">++</span><span style="color: #000000; ">)&nbsp;{<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snprintf(tmp,&nbsp;</span><span style="color: #0000FF; ">sizeof</span><span style="color: #000000; ">(tmp),&nbsp;</span><span style="color: #000000; ">"</span><span style="color: #000000; ">Cpu%-3d:</span><span style="color: #000000; ">"</span><span style="color: #000000; ">,&nbsp;smpcpu[i].id);<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp(</span><span style="color: #000000; ">&amp;</span><span style="color: #000000; ">smpcpu[i],&nbsp;tmp);<br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">}</span></div></div><div id="LC21" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div><div id="LC22" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cpu_tot为cpu数量。</div><div id="LC23" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cpus_refresh函数里从/proc/stat文件里读入cpu信息，然后装入smpcpu里。smpcpu为大小为Cpu_tot+1个CPU_t成员的数组。</div><div id="LC24" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/proc/stat文件的头几行为：</div><div id="LC25" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000; ">cpu&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />cpu0&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br />cpu1&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;</span><span style="color: #000000; ">%</span><span style="color: #000000; ">d&nbsp;<img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /><img src="http://www.cppblog.com/Images/dot.gif" alt="" /></span></div></div><div id="LC29" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;第一行的cpu信息装入smpcpu[Cpu_tot]，之后的cpu0\cpu1\...装入smpcpu[0]\smpcpu[1\...。</div><div id="LC30" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;View_CPUSUM这个由1键来控制的那个开关，开关关闭时只显示smpcpu的Cpu_tot，开关开启时显示的是smpcpu的下标0~Cpu_tot-1的成员。即，top的默认在开头显示的cpu详细信息显示的是/proc/stat的第一行处理后，按下1键，显示的时/proc/stat后续各cpu数据。</div><div id="LC31" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/proc/stat里都是数字，下边看看top里显示的百分比怎么算的。</div><div id="LC32" style="padding-left: 10px;"></div><div id="LC33" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CPU_t的定义：</div><div id="LC34" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;These&nbsp;typedefs&nbsp;attempt&nbsp;to&nbsp;ensure&nbsp;consistent&nbsp;'ticks'&nbsp;handling</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">typedef&nbsp;unsigned&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;TIC_t;<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">typedef&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;</span><span style="color: #0000FF; ">long</span><span style="color: #000000; ">&nbsp;SIC_t;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;This&nbsp;structure&nbsp;stores&nbsp;a&nbsp;frame's&nbsp;cpu&nbsp;tics&nbsp;used&nbsp;in&nbsp;history<br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;calculations.&nbsp;&nbsp;It&nbsp;exists&nbsp;primarily&nbsp;for&nbsp;SMP&nbsp;support&nbsp;but&nbsp;serves<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #008000; "></span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;all&nbsp;environments.</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">typedef&nbsp;</span><span style="color: #0000FF; ">struct</span><span style="color: #000000; ">&nbsp;CPU_t&nbsp;{<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIC_t&nbsp;u,&nbsp;n,&nbsp;s,&nbsp;i,&nbsp;w,&nbsp;x,&nbsp;y,&nbsp;z;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;as&nbsp;represented&nbsp;in&nbsp;/proc/stat</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIC_t&nbsp;u_sav,&nbsp;s_sav,&nbsp;n_sav,&nbsp;i_sav,&nbsp;w_sav,&nbsp;x_sav,&nbsp;y_sav,&nbsp;z_sav;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;in&nbsp;the&nbsp;order&nbsp;of&nbsp;our&nbsp;display</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;id;&nbsp;&nbsp;</span><span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;the&nbsp;CPU&nbsp;ID&nbsp;number</span><span style="color: #008000; "><br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #008000; "></span><span style="color: #000000; ">}&nbsp;CPU_t;</span></div></div><div id="LC48" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每次从/proc/stat取的数据称为一帧的数据，会从到CPU_t结构体的第一行成员里，上次的数据即上一帧的数据就拷到CPU_t的第二排带_sav后缀的成员里，一一对应。</div><div id="LC49" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;summaryhlp函数里计算我们想看的cpu各详细指标的百分比。只取部分代码或伪码做演示：</div><div id="LC50" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #000000; ">SIC_t&nbsp;u_frme,&nbsp;s_frme,&nbsp;n_frme,&nbsp;i_frme,&nbsp;w_frme,&nbsp;x_frme,&nbsp;y_frme,&nbsp;z_frme,&nbsp;tot_frme,&nbsp;tz;<br /></span><span style="color: #008080; ">&nbsp;2</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">&nbsp;3</span>&nbsp;<span style="color: #000000; ">u_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u_sav;<br /></span><span style="color: #008080; ">&nbsp;4</span>&nbsp;<span style="color: #000000; ">s_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s&nbsp;</span><span style="color: #000000; ">-</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s_sav;<br /></span><span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /></span><span style="color: #008080; ">&nbsp;6</span>&nbsp;<span style="color: #000000; ">tot_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;u_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;s_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;n_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;i_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;w_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;x_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;y_frme&nbsp;</span><span style="color: #000000; ">+</span><span style="color: #000000; ">&nbsp;z_frme;<br /></span><span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">if</span><span style="color: #000000; ">&nbsp;(tot_frme&nbsp;</span><span style="color: #000000; ">&lt;</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">)&nbsp;tot_frme&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">;<br /></span><span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #000000; ">scale&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100.0</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">/</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)tot_frme;<br /></span><span style="color: #008080; ">&nbsp;9</span>&nbsp;<span style="color: #000000; "><br /></span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #000000; ">us</span><span style="color: #000000; ">%</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)u_frme&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">11</span>&nbsp;<span style="color: #000000; ">sy</span><span style="color: #000000; ">%</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)s_frme&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;scale;<br /></span><span style="color: #008080; ">12</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /><br /></span><span style="color: #008080; ">13</span>&nbsp;<span style="color: #000000; ">cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u_sav&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">u;<br /></span><span style="color: #008080; ">14</span>&nbsp;<span style="color: #000000; ">cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s_sav&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;cpu</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">s;<br /></span><span style="color: #008080; ">15</span>&nbsp;<span style="color: #000000; "><img src="http://www.cppblog.com/Images/dot.gif" alt="" /></span></div></div><div id="LC67" style="padding-left: 10px;"></div><div id="LC68" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;每个进程占cpu百分比计算：</div><div id="LC69" style="padding-left: 10px;"><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008080; ">1</span>&nbsp;<span style="color: #000000; ">Frame_tscale&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">100.0f</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">/</span><span style="color: #000000; ">&nbsp;((</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)Hertz&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)et&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;(Rc.mode_irixps&nbsp;</span><span style="color: #000000; ">?</span><span style="color: #000000; ">&nbsp;</span><span style="color: #000000; ">1</span><span style="color: #000000; ">&nbsp;:&nbsp;Cpu_tot));<br /></span><span style="color: #008080; ">2</span>&nbsp;<span style="color: #000000; "></span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">&nbsp;u&nbsp;</span><span style="color: #000000; ">=</span><span style="color: #000000; ">&nbsp;(</span><span style="color: #0000FF; ">float</span><span style="color: #000000; ">)p</span><span style="color: #000000; ">-&gt;</span><span style="color: #000000; ">pcpu&nbsp;</span><span style="color: #000000; ">*</span><span style="color: #000000; ">&nbsp;Frame_tscale;</span></div></div><div id="LC73" style="padding-left: 10px;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;算的是两帧之间总时间片数量，各进程占的时间片数量百分比。</div></pre><img src ="http://www.cppblog.com/yangsf5/aggbug/204148.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-11-07 19:20 <a href="http://www.cppblog.com/yangsf5/archive/2013/11/07/204148.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>重拾博客一年多</title><link>http://www.cppblog.com/yangsf5/archive/2013/11/05/204104.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Tue, 05 Nov 2013 14:12:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/11/05/204104.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204104.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/11/05/204104.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204104.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204104.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/11/05/13-blog-reborn/"><div><span style="color:red;">http://blog.clawz.me/2013/11/05/13-blog-reborn/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/11/05/13-blog-reborn/"><div></div><p>&nbsp;</p></a><p><br /><br />&nbsp; &nbsp; 博客断断续续写了好几年，重拾博客的第一篇是2012年9月19日写的<a title="" href="http://www.cppblog.com/yangsf5/archive/2013/04/08/199222.html" target="_self" _href="http://www.cppblog.com/yangsf5/archive/2013/04/08/199222.html" data_ue_src="http://www.cppblog.com/yangsf5/archive/2013/04/08/199222.html">吐槽as3的接口</a>。这一年多每月都坚持写个2、3篇，纪念下。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这些年在多个地方写过（<a title="" href="http://www.cppblog.com/yangsf5/archive/2013/04/08/199225.html" target="_self" _href="http://www.cppblog.com/yangsf5/archive/2013/04/08/199225.html" data_ue_src="http://www.cppblog.com/yangsf5/archive/2013/04/08/199225.html">我的技术博客初衷</a>），  1年前的决定定在c++博客园了。最近又看到些用github pages写博客的文章，有股搞一搞的暗劲。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;在github写博客的优势就是我一直想要的一个功能，写的文章有版本管理，当自己修改某些文章的时候，看下历史记录就知道修改的原因了。另外隐约感觉github应该比博客园活的久。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;但是放github之后，会有人看吗，搜索引擎能很快收录吗？不得不再次思考自己博客的初衷&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;慢慢去想吧，无论放到哪，一定要坚持更新&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这一年多也有不少心得和经验没有写到博客里，有的可能是忙完后忘了总结，有时根本都没意识到那个东西挺值得总结的。另外这一年的博客也有些有充数嫌疑，汗，这点慢慢改正。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;特别讨厌很多博客转载别人的文章，所以我的博客里肯定是坚持原创，至少也是一番搜索了解某项技术后的总结（并给出原出处的链接且不赘述人家写完的）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;一直在考虑要不要写点技术外的东西，例如硬件相关的。想了下，硬件也是程序员的工具（工欲善其事必先利其器）啊，工具又不一定是软件写成的tool，所以以后碰到也可以写点儿。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204104.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-11-05 22:12 <a href="http://www.cppblog.com/yangsf5/archive/2013/11/05/204104.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>休闲游戏平台架构</title><link>http://www.cppblog.com/yangsf5/archive/2013/10/31/204033.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 31 Oct 2013 15:15:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/10/31/204033.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/204033.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/10/31/204033.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/204033.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/204033.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/10/31/13-game-platform/"><div><span style="color:red;">http://blog.clawz.me/2013/10/31/13-game-platform/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/10/31/13-game-platform/"><div></div><p>&nbsp;</p></a><p><br />一、背景和目标</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;当年大三的时候写了个五子棋世界，就是qq  game那种大厅-房间-桌子（我只有简单逻辑的五子棋）。毕业后一直想找个时间来重构它，后来有次下决心看了下代码，有点儿不知所措，你懂的，：D，还不如重写。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;现在对go很感兴趣，准备用go来实现以前的开源梦。就先已以前的五子棋世界那种休闲游戏平台来开始练手吧。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;目标暂时不定的太大，基本实现大厅-房间-桌子-游戏就行了，慢慢重构慢慢完善。</p> <p>&nbsp;</p> <p>二、服务器架构</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;基本架构参照之前给公司项目做的<a title="" href="http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html" target="_self" _href="http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html" data_ue_src="http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html">架构</a>。当架构有改变时，及时修改这篇博客，或者新博客与这篇相互引用和注解。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;不同的部分，加个大厅，大厅里显示房间状态，这样玩家就自己选择闲的房间去玩，这样就不需要做负载均衡的算法了。</p> <p>&nbsp;</p> <p>（一）账户系统</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;游戏自身不做账号密码这种用户系统，只用第三方的账户，如微博账户等来连接到我们游戏。或者更简单点，这块儿只模拟下微博等第三方用户系统的登陆了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;第三方账户连接到我们游戏，我们本地只由自增长的uid生成器来生成一个int的uid即可，将第三方的platformUid和我们的localUid做个关联映射。</p> <p>&nbsp;</p> <p>（二）大厅</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;大厅可以做成短连接，玩家选择游戏及房间的时候才去大厅刷新下当前的各房间负载情况。</p> <p>&nbsp;</p> <p>二、客户端</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;用walk。（待详细规划）</p><img src ="http://www.cppblog.com/yangsf5/aggbug/204033.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-10-31 23:15 <a href="http://www.cppblog.com/yangsf5/archive/2013/10/31/204033.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集群实现细节（2）-玩家在线状态续</title><link>http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sat, 19 Oct 2013 01:41:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203811.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203811.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203811.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/10/19/13-game-cluster-design-detail-2/"><div><span style="color:red;">http://blog.clawz.me/2013/10/19/13-game-cluster-design-detail-2/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/10/19/13-game-cluster-design-detail-2/"><div></div><p>&nbsp;</p></a><p><br />&nbsp;</p><p>一、玩家离线</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;由于离线的状况多，常见的玩家自己拿自己的账号的离线，也有自己的账号在多个设备来挤掉线，还有就是被非法的人使用时的挤掉线。这里应该将玩家理解为一个账号，下边尽量用账号来表述。</p> <p>（一）网络断开或者主动离开游戏</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这时玩家所在的服务器在玩家net.close时加入向通信redis汇报的逻辑，即通信redis里删除这个玩家的在线纪录。</p> <p>&nbsp;</p> <p>（二）同服重复登陆时的kick</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;首先肯定要踢掉之前登陆的链接。因为同服时新旧链接都在这个服务器上，逻辑上简单，允许新链接的登陆比较好处理，但是后边有其他考虑。</p> <p>&nbsp;</p> <p>（三）异服登陆时的kick</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;首先也是踢掉之前的登陆。需要在之前登陆到的服务器将该账号的链接断开并整理数据存储之后，才能允许在新的服务器登陆。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;旧服务器清理完该玩家后，向通信redis报告删除该账号的在线状态。新服务器需要知道玩家已经在旧服被kick完了才可以让玩家登陆。刚才同服时提到的允许新链接立刻登陆的问题，这里就变的比较不可控了。美好的过程是，新链接接入后挂起在新服，等异服踢完后，继续做新链接的登陆操作。但是这需要新旧服之间的同步逻辑，需要将新服玩家做个状态机为维护这种挂起或继续登陆状态。另外还要考虑这个期间玩家又在另一个服登陆。要考虑的东西很多&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;还有一种有问题的处理方式，即新服只是向老服发送踢人指令，新服自己却马上进入新链接的登陆操作。这样的问题是，即使业务逻辑简单到不会发生数据不同步问题，但登陆操作不会一定成功。新服登陆完向通信redis报告玩家在线，旧服踢完要向通信redis报告玩家离线。这两个操作异步时，如果旧服的离线报告在后，通信redis上就会错误的记录账号当前不在线&#8230;&#8230;</p> <p>&nbsp;</p> <p>（四）总结</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;最终重复登陆问题简单处理方法：账号登陆时，只要检测到该账号同服或异服已登陆，先将旧链接踢掉，再将新链接断开。就给玩家一个提示&#8220;账号已登录，请稍后重试&#8221;，让玩家自己来多操作几次，直到旧链接被踢完。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>二、同一账号的同瞬间多起登陆事件</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;上边重复登陆的检查还有一种情况不能防止，就是瞬间的多个客户端用同一账号登陆。同服时由于nodejs的异步，异服时由于天然异步，检查该账号是否已登陆与将当前链接成功登陆并向通信redis报告这些操作不具原子性。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;所以在最后向通信redis写入上线状态时再次判断是否已登陆（即判断是否被瞬时并发的另一个客户端的登陆给标记为已上线了）。redis里用hsetnx代替hset，前者在数据已经被设置时操作失败。</p> <p>&#8203;</p> <p>PS：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;刚接触不久或者本身逻辑就复杂的东西（例如分布式）很多思考的结果不及时记录的话，后边容易忘记当初的理由，导致需要冗余的重复思考。所以现在博客写琐碎些，记载些细节的思考。</p> <p>&nbsp;</p><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203811.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-10-19 09:41 <a href="http://www.cppblog.com/yangsf5/archive/2013/10/19/203811.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>集群实现细节（1）-异服通信和压测</title><link>http://www.cppblog.com/yangsf5/archive/2013/10/17/203784.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 17 Oct 2013 06:45:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/10/17/203784.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203784.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/10/17/203784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203784.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203784.html</trackback:ping><description><![CDATA[<p>&nbsp;</p><fieldset><legend><span style="color: #ff0000;">&nbsp;2016-07-11 日更新&nbsp;</span></legend><div><span style="color:red;">此篇博客已经迁移到新博客，并做行文检查和优化排版：</span></div><div></div><a href="http://blog.clawz.me/2013/10/17/13-game-cluster-design-detail-1/"><div><span style="color:red;">http://blog.clawz.me/2013/10/17/13-game-cluster-design-detail-1/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/10/17/13-game-cluster-design-detail-1/"><div></div><p>&nbsp;</p></a><p><br /></p><p>一、背景</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;项目开始后，先敲定了大体可横向扩展的集群架构（这是个美好的期望），然后开始编写单进程的服务器底层和逻辑，让前边几个迭代周期的逻辑内容配合客户端跑起来了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;接着就是将单进程的架构扩展起来，设计上细化下架构的扩展。已写在前篇《休闲手游服务器集群扩展思考》里。最近的两周在将之前单进程的服务器架构里部分模块扩展为支持这篇随笔里提到的集群架构。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;实现的过程中碰到的一些需要仔细设计的细节，原则上还是K.I.S.S。</p> <p>&nbsp;</p> <p>二、全服玩家在线状态</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;逻辑服务器集群的负载均衡算法还没实现。先只扩展玩家间的同服通信为异服通信（通过redis的pub/sub，以下将这个用于通信转发的redis简称为通信redis）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;问题链：（&#8220;--&gt;&gt;&#8221;引出的下个问题被当前问题所依赖）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通信发起方需要知道目标方在逻辑集群里的哪个服务器上  --&gt;&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;玩家登陆和退出时往通信redis报告  --&gt;&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;登陆时检查账号是否注册到我们的游戏，否就注册  --&gt;&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>（一）登陆和注册</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;玩家拿到用户系统的账号来登陆我们游戏服务器。游戏服务器拿client给的这个code再去用户系统服务器做验证，通过后继续。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;检查账号是否在我们游戏注册，如果没有则注册上，映射出游戏服务器上的一个local  uid。这里需要检查玩家是否在游戏注册了，所以需要一个platform uid与local  uid的映射表。这个映射之前单进程服务器时与其他角色数据放在相同redis上的，现在移到全局类的redis上（以下简称全局redis，暂时是将通信redis和全局redis放一起的，等以后看压测和线上反馈再做演变）。另外用来本地注册生成local  uid的自增长id也移到了全局redis上。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;检查完注册，得到local  uid，先看是否在本服务器登陆了，否则再向通信redis查看是否登陆在其他服务器。如果已登陆，则踢掉之前的登陆。之前单进程只有同服重复登陆踢人，现在多个异服重复登陆的踢人操作。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;登陆成功向通信redis报告local uid和所在的这个logic服务器的server  id。另外退出时也向通信redis报告，注销掉这条记录。</p> <p>&nbsp;</p> <p>（二）异服通信</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;每个逻辑服务器都与通信redis建立用于pub/sub的链接，各逻辑服务器有自己的频道。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;异服上的玩家通信时，从通信redis拿到目标玩家所在server  id，让后向目标server所对应的专有频道pub数据即可。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>三、压测工具</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;加了这个集群扩展后，底层测试只是单元测试是不够的。反正要压力测试工具迟早要写，就先写了简单版的压测工具，来做异服通信的自动化测试。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;压测工具开始的想法挺多的，后来抛弃了一些短期不好实现的想法。现在就简单的，一个client一个Client  struct，这个处理client的通信发送接收。做相同动作的client为一个Group struct。每个动作为一个Rule  struct，里边组合好收到什么包后做什么事情，或者直接发些什么包。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;c++端游压测的每个Rule动作一般用lua来写的，比较方便，我们这个压测工具用go写，rule暂时也用go写，也不麻烦。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;感慨下，这种并行的应用场景，go的编程思维与具体写法比node.js更适合c/c++出身的程序员。</p><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203784.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-10-17 14:45 <a href="http://www.cppblog.com/yangsf5/archive/2013/10/17/203784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>休闲手游服务器集群扩展思考</title><link>http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Mon, 30 Sep 2013 02:46:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203500.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203500.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203500.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/30/13-mobile-game-cluster-design/"><div><span style="color:red;">http://blog.clawz.me/2013/09/30/13-mobile-game-cluster-design/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/09/30/13-mobile-game-cluster-design/"><div></div><p>&nbsp;</p></a><p><br />一、目标</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;能横向扩展，架构要简单，能做到负载均衡，避免单节点负载太轻的资源浪费。</p> <p>&nbsp;</p> <p>二、数据存储的DB集群</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;数据存储类型有多种。</p> <p>（一）非交互性的个人数据</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;可通过简单的id分段。id为1~10000的玩家个人数据存储在db1，id为10001~20000的玩家个人数据存储在db2，以此类推。</p> <p>&nbsp;</p> <p>（二）交互性数据</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;如好友关系等。</p> <p>（1）如果好友关系可以为单向，那么可以将关系存到个人数据里。</p> <p>（2）如果好友关系不能为单向，那么需要保证每条关系保持在要么没有，要么两人都认同，记数据上一直，互相有关系。那么需要保证相关的关系操作的一致性。这样可能只保存一份每两个人之间的关系，k-v存储时需要方向查找，不知是否能实现。</p> <p>&nbsp;</p> <p>（三）全局数据</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;如全局排行榜之类的。这种放在单独的库里里，专门做全局数据的存储。当到一定规模时，按全局数据的类型再分库。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;家族、帮会等，也放单独的库里。如果需要扩展，再按家族id、帮会id来分库。</p> <p>&nbsp;</p> <p>三、逻辑服务器集群对DB集群的访问</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;DB集群的路由规则配置到逻辑服务器的config里。当需要热扩展DB时，启动新DB后，给各logic服务器发送GM指定，reload路由规则的config。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;DB集群路由规则的config，可以放在一个公共地方，各logic服务器接到GM指令后，去公共地方拉取新的config然会reload。</p> <p>&nbsp;</p> <p>四、逻辑服务器集群</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;为了架构的简单，可以每个逻辑服务器进程上都有所有逻辑，扩展时，以扩展逻辑服务器进程数量来达到。</p> <p>（一）各逻辑服务器上玩家分配</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;逻辑服务器集群之间的交互。如果逻辑服务器的使用，也像个人数据存储的DB那样id分段&#8212;&#8212;只让1~10000的玩家登陆logic1，10001~20000的玩家登陆logic2时，这很简单，但各id断的玩家活跃度不定的，做不到负载均衡啊。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;所以是根据当时的负载情况，来推荐玩家登陆闲的逻辑服务器的。这样需要有个全局映射，知道哪个玩家登陆在哪个服务器上。可以将玩家当前所在的服务器id记录在该玩家的个人数据所在的db里。</p> <p>（二）逻辑服务器间的通信</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;目前项目持久化使用redis，最快出东西，就先考虑redis的优势。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;逻辑服务器间的通信，通过全局数据存储的redis来做pub/sub转发吧。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;redis的pub和sub的实时性不够时，&#8203;将有实时性需求的玩家都转到一个专门做强实时性的特殊逻辑服务器。</p> <p>&nbsp;</p> <p>五、PS</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;公司的项目是Node.js+Redis，业余时间打算用Go写个服务器引擎。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这篇考虑发到精华区，可以得到很多的批评建议。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203500.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-30 10:46 <a href="http://www.cppblog.com/yangsf5/archive/2013/09/30/203500.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开始学习Common Lisp</title><link>http://www.cppblog.com/yangsf5/archive/2013/09/15/203239.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Sun, 15 Sep 2013 03:25:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/09/15/203239.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/203239.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/09/15/203239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/203239.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/203239.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><span style="color:red;"><a href="http://blog.clawz.me/2013/09/15/13-common-lisp/"><span style="color:red;">http://blog.clawz.me/2013/09/15/13-common-lisp/</span></a></span></div></fieldset><div><span style="color: red;"><a href="http://blog.clawz.me/2013/09/15/13-common-lisp/"></a></span></div><p><br />一、为何想学lisp</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;最初了解lisp是从《黑客与画家》里，里边的黑客强烈推荐程序员用lisp，并有部分讲《为什么lisp语言如此先进？》，书是阮一峰翻译的，这节在他的博客也有节选：</p> <p><a href="http://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html" _href="http://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html">&nbsp;&nbsp;&nbsp;&nbsp;&#8203;http://www.ruanyifeng.com/blog/2010/10/why_lisp_is_superior.html</a></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;总结一下：</p> <p>a.  越近代的语言越像lisp；而当前最新潮的语言也只是实现了lisp作者在1958年的设想，因为lisp设计目的是数学理论演算而不是语言这种本质上的一种技术。技术会过时而数学不。今天最高级的主流语言，也只是刚刚接近lisp的水平。虽然已经接近，但还是没有lisp那么强大。</p> <p>b. 等等，其他不一一摘抄。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;其中一点提到，&#8220;一行lisp代码相当于20行C代码&#8221;。lisp会缩短开发周期，而且还是c能做lisp所有事情的前提下。文中举例说，如果你用其他语言跟别人lisp语言的公司竞争，同样的功能你就比别人慢很久才能开发完，竞争就出于劣势。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;其他在网络上看到的lisp相关言论：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;起名为&#8220;格林斯潘第十定律&#8221;（Greenspun's Tenth  Rule）：&#8220;任何C或Fortran程序复杂到一定程度之后，都会包含一个临时开发的、只有一半功能的、不完全符合规格的、到处都是bug的、运行速度很慢的Common  Lisp实现。&#8221;</p> <p>&nbsp;</p> <p>二、学习过程中</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外还有个原因，最近想了解函数式编程，想了解下支持分布式原语的erlang，先学哪个还是纠结了下的。  后来考虑到新到的项目中想设计成分布式扩展方便的服务器架构，就优先学下erlang。先花几天把《Erlang程序设计》给看完了，看的很激动，但是考虑到项目人员现状及将来的维护，项目没用erlang，用了node.js。</p> <p>&nbsp;&nbsp;&nbsp;  之后又花几天把许式伟他们写的《Go语言编程》看完了。go语言确实不错，以后可以考虑用这个写个游戏服务器引擎什么的。本想立即就开动，但是项目属于开始搭架子阶段，需要思考的时间挺多，回家可以利用的时间不多，专心写开源项目不现实。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;于是回家的时间先学Common Lisp（以下简称cl），现在正在看田春翻译的《实用Common  Lisp编程》，看到12.6映射。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;cl很多东西跟类c的语言差别就比较大了，看的进度还是挺慢的。看着看着，一边惊叹他强大的表现力，一边有点害怕太庞大，以后实用起来不顺利。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;如果找份cl的工作，国内大小公司估计都不大好找。除非能在一个高手云集的团队里，大家又都喜欢cl，而且我们有话语权&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;所以将来cl在为了更好的思考编程之外，很可能只是用来写些脚本或者自己的玩具什么的。近期的应用可能是生成javascript代码。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;等cl学的不错了，可以做些个人项目的快速开发&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;</p> <p>三、我了解Common Lisp一些资料</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;建议一下书籍，按阅读顺序（在知乎看到的，别的地方推荐也大同小异）：<br />《Structure and  Interpretation of Computer Programs》（SICP）可以启发思想，尤其是函数式编程入门；<br />《Practical  Common Lisp》和《Land of Lisp》也适合初学者；<br />《On Lisp》主要讨论macro的使用；<br />《Let over  Lambda》在《On Lisp》基础上更深入讨论宏。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8203;《On Lisp》和《Practical Common Lisp》（中译为《实用Common  Lisp编程》） 由田春翻译完成。我个人先买了SICP，但是里边是讲Scheme，看了几节怕到时学lisp会混乱，就转先实用lisp这本了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;另外我用的实现是Steel Bank Common Lisp。</p> <p>&nbsp;</p> <p>&nbsp;四、附上这段时间了解的函数式语言个人简介</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这条自己的理解，纯粹为了自己做个笔记。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;haskell貌似比较新，应用不多，别说是分布式，就是普通应用也不多。haskell是纯函数式。而lisp不是纯的，还可以以别的方式来编程。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;erlang倒是主打分布式。erlang内置了多台机器之间的通讯原语，程序员只用关心业务逻辑就可以了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;lisp主要是一种全新的看待软件开发的视角。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;&#8203;go也支持闭包。</p> <p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/203239.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-15 11:25 <a href="http://www.cppblog.com/yangsf5/archive/2013/09/15/203239.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><item><title>facebook接入</title><link>http://www.cppblog.com/yangsf5/archive/2013/08/08/202411.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 08 Aug 2013 04:53:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/08/08/202411.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/202411.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/08/08/202411.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/202411.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/202411.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><div><span style="color:red;"><a href="http://blog.clawz.me/2013/08/08/13-facebook-connect/">http://blog.clawz.me/2013/08/08/13-facebook-connect/</a></span></div></fieldset><p>一、需求</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;我方游戏服务器为一套nodejs框架下开发的，手机App前端为javascript。现在需要将游戏接入facebook，要求能用facebook登陆我方游戏，并可以取到玩家的facebook好友等信息、可以向好友送礼，还可以向玩家facebook增加游戏状态。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果为前端接入，需要封装出js的接口。</p> <p>&nbsp;</p> <p>二、接入方式</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;需求里涉及到了玩家间的利益交互，如这里的可以向好友送礼。需要确认游戏里这些利益交互（现在的利益可能较弱，但需要考虑将来的利益交互规划）被外挂刷后是否对游戏有影响。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;如果影响较大，例如刷了很多物品，让游戏失去平衡&#8212;&#8212;RPG里可能是装备特牛，休闲游戏可能是道具很多，更有利于冲击排行榜等。就需要将facebook的接入方式定为server-side接入。如果影响较小，就无所谓，可以像单机游戏那样在前端做接入，facebook的好友信息等由前端传到我们服务器。</p> <p>&nbsp;</p> <p>（一）server-side接入</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;官方的<a href="https://developers.facebook.com/docs/sdks/" _href="https://developers.facebook.com/docs/sdks/">https://developers.facebook.com/docs/sdks/</a>&nbsp;里收录的第三方nodejs的sdk在<a href="https://github.com/amachang/facebook-node-sdk" _href="https://github.com/amachang/facebook-node-sdk">https://github.com/amachang/facebook-node-sdk</a>。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这种是nodejs开的本地网站，然后本地网站可以开个网址做facebook的接入验证，之后取玩家的facebook信息，可以调封装好的facebook  API。效果可以开代理看下<a href="http://claw-fb-off.herokuapp.com/" _href="http://claw-fb-off.herokuapp.com">http://claw-fb-off.herokuapp.com</a>。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;但是不知我们服务器的nodejs和前端App的js之间是否支持这种网页式的交互。咨询了nodejs框架组的同学，表示不行，我自己没做过这方面的东西，所以还是要请游戏组同学看看。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;另外咨询了众多项目组，做过接入的都是前端接入，还没有做过server-side接入的。</p> <p>&nbsp;</p> <p>（二）client-side接入</p> <ol list-paddingleft-2"=""> <li> <p>官方提供native IOS和Android API的SDK。</p></li> <li> <p>另外也提供javascript SDK（<a href="https://developers.facebook.com/docs/reference/javascript/" _href="https://developers.facebook.com/docs/reference/javascript/">https://developers.facebook.com/docs/reference/javascript/</a>），貌似也是网页形式，不知我们前端是否支持？</p></li> <li> <p>EziSocial-Plugin为C++编写，但是这个是收费的，游戏组确认要用吗？</p></li></ol><img src ="http://www.cppblog.com/yangsf5/aggbug/202411.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-08 12:53 <a href="http://www.cppblog.com/yangsf5/archive/2013/08/08/202411.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>懒人厨房</title><link>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Wed, 17 Jul 2013 13:13:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201910.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201910.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201910.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/07/17/13-lazy-cook/"><div><span style="color:red;">http://blog.clawz.me/2013/07/17/13-lazy-cook/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/07/17/13-lazy-cook/"><div></div><p>&nbsp;</p></a><p>&nbsp;</p><div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; 有时候忙了一天下班后，和女朋友都不想做饭，女朋友就受懒人天气app（里边突出显示重要信息，其他都没有，这样一眼就能看到想要的）的影响，考虑写个懒人厨房的app。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;其实女朋友想的懒人厨房跟那个懒人天气的关联就是&#8220;懒人&#8221;，：）</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;女朋友在看android方面的资料，暂时又得快速写好app，我就先在github开个项目，先把想到的菜名给记下来吧，以后再慢慢看怎么去演变这个项目&#8212;&#8212;是只做开放文档形式，还是演变成个app之类的。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;项目网址：<a href="https://github.com/yangsf5/claw-lazycook">https://github.com/yangsf5/lazycook</a></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 /> &nbsp; &nbsp; &nbsp;这个后来没搞起来，老婆那也不想做了，哈哈哈。</div><div style="font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: medium;">&nbsp; &nbsp; &nbsp;简单谈下这个事情吧，感觉做菜复杂的话太耗费时间，可以靠多练习来增加熟练度，各个步骤也慢慢根据经验来优化，来做好时间统筹。</div></div><p><a href="https://github.com/yangsf5/claw-lazycook"></a></p><img src ="http://www.cppblog.com/yangsf5/aggbug/201910.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-07-17 21:13 <a href="http://www.cppblog.com/yangsf5/archive/2013/07/17/201910.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>TopN动态排行榜实现</title><link>http://www.cppblog.com/yangsf5/archive/2013/07/12/201725.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 12 Jul 2013 05:05:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/07/12/201725.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201725.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/07/12/201725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201725.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201725.html</trackback:ping><description><![CDATA[<p>&nbsp; &nbsp; &#8203;目前只是简单的封装了stl的heap相关算法：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;<a href="https://github.com/yangsf5/claw-gse/blob/master/src/claw/gse/top_n.h">https://github.com/yangsf5/claw-gse/blob/master/src/claw/gse/top_n.h</a></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;&#8203;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/201725.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-07-12 13:05 <a href="http://www.cppblog.com/yangsf5/archive/2013/07/12/201725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>protobuf与shared memory</title><link>http://www.cppblog.com/yangsf5/archive/2013/06/26/201309.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Tue, 25 Jun 2013 16:03:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/06/26/201309.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201309.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/06/26/201309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201309.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201309.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/06/26/13-protobuf-shared-memory/"><div><span style="color:red;">http://blog.clawz.me/2013/06/26/13-protobuf-shared-memory/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/06/26/13-protobuf-shared-memory/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; &#8203;项目里shared  memory存放的数据结构，现在需要将其同时用于server与client之间的相应数据交互。server与client之前的协议格式为protobuf。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;为了只维护一份代码，准备将之前用于shared  memory的结构转化为protobuf，然后两处都用这个protobuf。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;搞了一会儿，才想起shared memory里只适合存定长的非指针结构。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;汗，这个几年前就经历过，那个时候是学生时代做五子棋世界的时候，貌似是想往shared  memory里存放std::map。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;当时水平太低，报错了就放弃了stl的容器，写些了中规中矩的结构体。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这次就顺便搜下当年那个问题的解决方法。找到个说的挺好的：<a href="http://www.cnblogs.com/fullsail/archive/2013/01/20/2868898.html" _href="http://www.cnblogs.com/fullsail/archive/2013/01/20/2868898.html">http://www.cnblogs.com/fullsail/archive/2013/01/20/2868898.html</a>。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;大意就是，stl里容器会动态分配内存，而且new的东西在自己的进程空间里，别的进程访问时必然是个不对的指针。需要将stl的分配器定制为从共享内存里分配空间，或者其他几个链接里提到的方法。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;回到我现在遇到的protobuf这个问题，protobuf里有些如repeated或者string等会动态new，这个如果做内存分配的定制，还得重改protobuf的代码，复杂度比较高。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;加上项目里的这单个协议格式制定的需求只是临时的，就更没必要了。最终放弃protobuf结构直接映射到共享内存的企图。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/201309.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-06-26 00:03 <a href="http://www.cppblog.com/yangsf5/archive/2013/06/26/201309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IncrediBuild编译问题</title><link>http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Tue, 25 Jun 2013 04:53:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201288.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201288.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201288.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/06/25/13-incredibuild-problem/"><div><span style="color:red;">http://blog.clawz.me/2013/06/25/13-incredibuild-problem/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/06/25/13-incredibuild-problem/"><div></div><p>&nbsp;</p></a><p><br />&nbsp; &nbsp; 自己工作机在vc点incredibuild编译时总是显示fail to create  process，周围同事却都没问题。这里记下解决的过程。</p> <p>&nbsp;</p> <p>一、fail to create process</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这个错误提示，第一反应就是用户没权限，查看了用户之后，提示这个用户就是管理员。后来各种倒腾都无果。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;权限的问题一时没解决，想别的办法&#8230;&#8230;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;试出一个办法：点开任务栏右下角的IncrediBuild  Agent，右键选择Build-&gt;open后打开的Batch Build里编译是完全没有问题的，没有那个创建进程失败的问题。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#8203;所以想，是不是因为vc的插件运行时的编译配置有问题，而在Agent独立进程里的Batch  Build里的编译配置比较纯净（例如不用搞那个cmake之类的检查）。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;于是找到Agent开启Batch  Build时的进程为BatchFile.exe，但是在自己写的bat里单独启动BatchFile，启动后弹出Batch  Build，选择编译后却也还是创建不了进程错误。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;偶然在vc的工具栏的IncrediBuild选项里也发现了Batch Build选项，弹出的Batch  Build也是不能创建线程。再次扫兴。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;所以想，是不是因为做为vc的插件和bat里启动运行时没有创建进程的权限。而在Agent独立进程里运行时能拿到权限？</p> <p>&nbsp;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;最后某此搜什么东西，憋见一个说法，&#8220;右键菜单win7管理员身份运行&#8221;。如果就特么搞定了。&nbsp;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff0000">解决办法大概是：<span style="color: #000000">win7启动vc时以管理员身份运行，程序鼠标右键有那个选项。另外也可以看看快捷方式里设置。之后从vc里load你的项目。</span>更方便的是将你的vc程序，打开属性的兼容性标签，特权等级里勾上以管理员身份运行此程序。<span style="color: #000000">（设置之后我在TC里不能直接双击启动**.sln，只好右键选择vc来启动）</span></span></p> <p>&nbsp;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;随后想是不是TotalCommand里起的进程没管理员权限，后来试了试不是这样的&#8230;&#8230;</p> <p>&nbsp;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;总结，我的win7用户不是真宗的管理员，虽然控制面板里提示了是！</p> <p>&nbsp;</p> <p>二、其他问题</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;有时编译完后不能自动stop build，还得手动点。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;这个看看进程管理器里好多僵死的build相关进程，全干掉。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/201288.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-06-25 12:53 <a href="http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【msvc调试】客户端某个流程后server卡住</title><link>http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 21 Jun 2013 04:40:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201196.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201196.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201196.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/06/21/13-debug-server-hang/"><div><span style="color:red;">http://blog.clawz.me/2013/06/21/13-debug-server-hang/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/06/21/13-debug-server-hang/"><div></div><p>&nbsp;</p></a><p><br /><br />&nbsp;&nbsp;&nbsp;单步到崩溃地点，有数组取数据和拷贝操作，猜测数组越界导致的栈溢出。就开始找越界检查工具。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;vs自身带的/GS只是在栈溢出时蹦个异常，不会给你定位崩在哪。所以找了会儿别的工具，boundschecker还没找到下的地方，IBM的purify跨平台但是收费，另外免费好用的就是linux下的valgrind了。这几种内存检查工具都可以检查内存泄露和越界之类的。只是项目现在赶进度，linux平台的编译还没时间解决，内存统一检查就作罢。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;开始看看能不能查dump。dump不是原生的dmp而是历史代码里重存为别的了。vc调试不很熟练，就索性把重存dump那块儿的catch给干掉了。直接让编译器崩到代码块儿再看看能不能看出什么问题。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;崩停到具体代码行了，很惊喜，赶紧看看各变量内存状况，问题数组是一个指针数组，这次惊喜的发现之前单步的那个下标对应在数组元素指针跟别的不一样，为0xcdcdcdcd，确认了下为vc下为未初始化的指针。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这样就好查了，问题定位到了，后边的就不啰嗦了。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;最终问题是，同事给一个类新加了几个指针成员，但是这几个没有new出来初始化之。唉&#8230;&#8230;只能感叹下敏捷开发那本书里说的，架构师要参加编码，我觉得要加点儿，就是架构师要参与编码还要参与测试调试自己的代码。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/201196.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-06-21 12:40 <a href="http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【msvc调试】server初始化时卡在某个点</title><link>http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 21 Jun 2013 04:38:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/201195.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/201195.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/201195.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/06/21/13-vc-debug-while/"><div><span style="color:red;">http://blog.clawz.me/2013/06/21/13-vc-debug-while/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/06/21/13-vc-debug-while/"><div></div><p>&nbsp;</p></a><p><br />&nbsp;&nbsp;&nbsp;&nbsp;初步调试，发现某个类的构造函数进了，但是在左花括号的地方就卡住了，没有往后走。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;一开始挺惊奇，过会儿就想到，类的构造函数里会被编译器插入一些没有显示初始化的成员的初始化语句。所以讲F10改为F11调试。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;慢慢似乎找到问题函数了，正准备再重开调试继续跟时，朋友表示按下vc的暂停键，照做，&#8220;我擦&#8212;&#8212;&#8221;之后是崇拜的口水。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;问题原因：while的退出变量没有自增，导致死循环了。<br /><br /></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;总结：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;程序卡在哪儿，基本就是死循环或者死锁。死循环的发现，可以看cpu占用来佐证。问题定位，暂停调试。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;死锁的定位，可以看stack，里边应该有wait之类的。</p><img src ="http://www.cppblog.com/yangsf5/aggbug/201195.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-06-21 12:38 <a href="http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>调试笔记集锦</title><link>http://www.cppblog.com/yangsf5/archive/2013/05/31/200714.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 31 May 2013 03:48:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/05/31/200714.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/200714.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/05/31/200714.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/200714.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/200714.html</trackback:ping><description><![CDATA[<p>一、gcc</p> <p>&nbsp;</p> <p>二、msvc<br />1.【msvc调试】server初始化时卡在某个点：<a href="http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html">http://www.cppblog.com/yangsf5/archive/2013/06/21/201195.html</a></p><div>2.【msvc调试】客户端某个流程后server卡住：<a href="http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html">http://www.cppblog.com/yangsf5/archive/2013/06/21/201196.html</a></div><div>&nbsp;</div> <p>&nbsp;</p><p>三、golang</p> <p>&nbsp;</p><p>1. json文件映射到内存失败</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;json文件里的字符串必须用双引号。<a title="" href="http://www.json.org/json-zh.html" target="_self" data_ue_src="http://www.json.org/json-zh.html">官方标准json</a>的字符串就只能双引号，只是js这种允许单引号，所以之前js的程序里可以解析单引号的json配置文件。</p><p>&nbsp;</p><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/200714.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-05-31 11:48 <a href="http://www.cppblog.com/yangsf5/archive/2013/05/31/200714.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>msvc编译问题集锦</title><link>http://www.cppblog.com/yangsf5/archive/2013/05/10/200165.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Fri, 10 May 2013 09:12:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/05/10/200165.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/200165.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/05/10/200165.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/200165.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/200165.html</trackback:ping><description><![CDATA[<p>&nbsp;</p><p>1.  链接libprotobuf.lib时，报与系统某库冲突，vc建议忽略系统库。这个有可能会出现别的问题。解决办法就是将protobuf的编译&#8220;运行库&#8221;设置和自己工程的设置成同一个，例如均为/MDd时就ok了。</p> <p>&nbsp; &nbsp;这个还是linux下gcc舒服。</p> <p>2. IncrediBuild编译问题：<a href="http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html">http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html</a></p> <p>3. Debugging information for *.exe cannot be found or does not match：</p> <p><a href="http://www.cnblogs.com/ustcwhc/archive/2012/04/05/2432829.html">&nbsp;&nbsp;&nbsp;&nbsp;&#8203;&#8203;http://www.cnblogs.com/ustcwhc/archive/2012/04/05/2432829.html</a></p><p><a href="http://www.cppblog.com/yangsf5/archive/2013/06/25/201288.html"><br /></a></p><img src ="http://www.cppblog.com/yangsf5/aggbug/200165.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-05-10 17:12 <a href="http://www.cppblog.com/yangsf5/archive/2013/05/10/200165.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>X项目C++服务器（1）- 总体构想</title><link>http://www.cppblog.com/yangsf5/archive/2013/04/25/199704.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Thu, 25 Apr 2013 06:52:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/04/25/199704.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/199704.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/04/25/199704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/199704.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/199704.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><p>&nbsp;</p><a href="http://blog.clawz.me/2013/04/25/13-x-cpp-server/"><p><span style="color:red;">http://blog.clawz.me/2013/04/25/13-x-cpp-server/&nbsp;</span></p></a></fieldset><a href="http://blog.clawz.me/2013/04/25/13-x-cpp-server/"><p>&nbsp;</p><p>&nbsp;</p></a><p>一、简介</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;这个项目刚起步，将来有可能会演变为公司的服务器框架。博客里暂且称呼为X项目。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;语言为c++，之后将此服务器的设计演变尽量记录下来，为一个系列，以&#8220;X项目C++服务器&#8221;为统一标题开头。</p> <p>&nbsp;</p> <p>二、架构设计</p> <p>（一）多进程通信方案</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;zeromq</p> <p>（二）协议方案</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;protobuf&nbsp;</p> <p>（三）存储</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;redis</p> <p>（四）脚本</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;luaplus</p> <p>（五）日志</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;glog</p> <p>&nbsp;</p> <p>三、自动构建部署</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;自动构建等为敏捷开发提供保障。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;之前经历的那些项目（其中包括业内比较有名的2个大型项目）在自动构建部署方面基本为0，开发效率不高，这次新项目准备从一开始就做这方面的准备。</p> <p>（一）单测</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;单测框架考虑google的gtest。</p><p>&nbsp;</p><img src ="http://www.cppblog.com/yangsf5/aggbug/199704.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-04-25 14:52 <a href="http://www.cppblog.com/yangsf5/archive/2013/04/25/199704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cmake用cotire设置gcc的预编译头</title><link>http://www.cppblog.com/yangsf5/archive/2013/04/23/199658.html</link><dc:creator>Sheppard Y</dc:creator><author>Sheppard Y</author><pubDate>Tue, 23 Apr 2013 06:10:00 GMT</pubDate><guid>http://www.cppblog.com/yangsf5/archive/2013/04/23/199658.html</guid><wfw:comment>http://www.cppblog.com/yangsf5/comments/199658.html</wfw:comment><comments>http://www.cppblog.com/yangsf5/archive/2013/04/23/199658.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/yangsf5/comments/commentRss/199658.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/yangsf5/services/trackbacks/199658.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/04/23/13-cmake-gcc-precompile/"><div><span style="color:red;">http://blog.clawz.me/2013/04/23/13-cmake-gcc-precompile/</span></div></a></fieldset><a href="http://blog.clawz.me/2013/04/23/13-cmake-gcc-precompile/"><div></div><p>&nbsp;</p></a><p><br /><br />一、预编译头</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;当工程大了，单机编译速度会很慢。预编译头会提高很大的速度。相关原理这里不赘述，网上很多。（或者老夫有空的时候再补充）</p> <p>&#8203;</p> <p>二、cmake设置gcc的预编译头</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;一开始google到一个国内同行写的cmake宏，用了下，貌似不是很好用。另外作者也表示还是有bug。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;后来找到cotire。目前使用良好。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;</p> <p>三、cotire（compile time reducer）</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;项目地址<a href="https://github.com/sakra/cotire" data_ue_src="https://github.com/sakra/cotire">https://github.com/sakra/cotire</a>。具体使用方式github里对应项目主页已经写的很清楚了（主页man看不明白的可以去看他的src里那个例子），这里只做下快捷备忘。</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;步骤：</p> <p>1. clone这个git。</p> <p>2. 将cotire里的CMake/cotire.cmake拷到咱们自己工程的顶层CMakeLists.txt同级目录下。</p> <p>3. 往这个顶层CMakeLists.txt里设置一个变量并include：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;set&nbsp;(CMAKE_MODULE_PATH&nbsp;"${CMAKE_SOURCE_DIR}/CMake")</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;include(cotire)</p> <p>4. 在具体的CMakeLists.txt的add_executable后边再cotire下，如：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;add_executable(MyExecutable&nbsp;${MyExecutableSources})<br />&nbsp;&nbsp;&nbsp;&nbsp;&#8203;target_link_libraries(MyExecutable&nbsp;${MyExecutableLibraries})<br />&nbsp;&nbsp;&nbsp;&nbsp;&#8203;cotire(MyExecutable)</p> <p>5. 上边是自动寻找预编译头，也可以自己设置，例如我们从vc跨平台过来的项目，显示设置stdafx.h，只用在cotire前边设置下即可：</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&#8203;set_target_properties(MyExecutable&nbsp;PROPERTIES&nbsp;COTIRE_CXX_PREFIX_HEADER_INIT&nbsp;"stdafx.h")<br />&nbsp;&nbsp;&nbsp;&nbsp;&#8203;&#8203;cotire(MyExecutable)</p><img src ="http://www.cppblog.com/yangsf5/aggbug/199658.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-04-23 14:10 <a href="http://www.cppblog.com/yangsf5/archive/2013/04/23/199658.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>