﻿<?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++博客-战魂小筑-随笔分类-网络 服务器技术</title><link>http://www.cppblog.com/sunicdavy/category/11297.html</link><description>讨论群:309800774 知乎关注:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxu</description><language>zh-cn</language><lastBuildDate>Mon, 27 Dec 2021 16:47:54 GMT</lastBuildDate><pubDate>Mon, 27 Dec 2021 16:47:54 GMT</pubDate><ttl>60</ttl><item><title>Event对应Entitas的GetTrigger+Collector</title><link>http://www.cppblog.com/sunicdavy/archive/2021/12/27/217896.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 27 Dec 2021 11:05:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2021/12/27/217896.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/217896.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2021/12/27/217896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/217896.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/217896.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Entitas的ECS系统 1. 本来在一个对象中添加一个类字段的过程，ECS需要添加一个类代表Component，并且代码生成。 这个字段一般用于描述对象的资源，处理显示的GameObject， 表示对象的类型等。 2. 本来一个对象的业务逻辑处理过程直接用方法解决的， ECS需要新加一个System，而操作对象需要使用Filter或Group查询获得。 3. 一系列的操作， 需要拆分为多个Sy...&nbsp;&nbsp;<a href='http://www.cppblog.com/sunicdavy/archive/2021/12/27/217896.html'>阅读全文</a><img src ="http://www.cppblog.com/sunicdavy/aggbug/217896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2021-12-27 19:05 <a href="http://www.cppblog.com/sunicdavy/archive/2021/12/27/217896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏与Web的服务器对比</title><link>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 29 Aug 2018 03:16:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/215887.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/215887.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/215887.html</trackback:ping><description><![CDATA[<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">为了编写基于</span><a href="https://github.com/davyxu/cellnet"><span style="font-size: 16px; color: #003884;">cellnet</span></a><span style="font-size: 16px; color: #333333;">的新一代游戏服务器框架，最近深入研究微服务，ServiceMesh等概念。研究过程中对Web和游戏两种服务器架构设计有一些心得，编写并记录下来。(下文中，Game表示游戏服务器，Web表示Web服务器) `` </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">状态缓存</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">所谓状态缓存，就是在内存而非专业数据缓存服务器（如redis）中保存和处理逻辑数据，手动编写此过程较为繁琐但是效率较高，但随着状态逻辑复杂性和并发、扩容问题提出，状态同步会变得越来越复杂。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">强交互性的服务器类型需要在服务器做缓存，逻辑编写也较为容易，无需处理事务并发问题。例如：组队，匹配，战斗逻辑。服务器不能随意重启。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">弱交互性的服务器类型可配合redis做成无状态服务器，例如：养成，技能升级，领取物品等。服务器随时支持重启。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器为了提高性能，早期所有服务器都是使用状态缓存写法编写，特别是MMORPG这类强交互的游戏服务器尤为严重。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">均为无状态服务器，弱交互。使用事务方式处理并发逻辑，例如：交易，下单等。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">推送，单独发送</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">这里提到的所谓推送，单独发送是与RPC区别的通讯方法。RPC要求请求必须有回应。而推送单独发送则更像是通知和广播，无需目的方返回任何消息。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">找到服务器的Session，直接Send</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">通过中转服务器，或称为中心服务器进行注册/广播</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">客户端的model数据需要更新时，服务器会主动推送消息。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器没有严格的RPC设计需求，推送和单独发送较Web服务器更多。而且游戏服务器多使用长连接，所以主动推送也比Web服务器来的方便一些。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">将推送做成专有的服务，并做排队和并发处理。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">可用性</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">听说过游戏停服更新，支付宝服务器在刷二维码时停服了可一定被骂惨吧。Web对服务器高可用性要求很高，游戏虽然也注重服务器稳定性和可用性，但是由于版本迭代更新频繁，停服更新反而能获得玩家接受。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏对可用性要求不高。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏大版本更新时需要停服更新。支持热更新技术的服务器（例如Erlang，Skynet）仅使用热更新修复bug，很少直接更新新版本。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">不是所有的游戏服务器支持动态添加服务器。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">极高的可用性，服务不允许停服更新，使用蓝绿及灰度方式更新服务器。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">随时可以横向扩展服务器，提高服务器容量和承载。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">连接及传输</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">均使用TCP传输协议，游戏服务器注重性能，自有协议及二进制协议使用较多。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web注重兼容和接口友好，使用JSON格式较多。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用长连接，需要从逻辑层维护连接状态及处理服务器不在线情况</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用自有封包格式，大部分使用protobuf或二进制流格式。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">微服务大部分使用短连接，grpc支持http2长连接</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用json编码方便调试和版本兼容。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">流量限制</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">人数多了，任何服务器都扛不住，流量限制和登入限制能有效保护服务器稳定。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">单服有人数限制，可以通过GM后台设置挡墙，超过无法进入</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">限流器中间件，可以精确到服务控制流量</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">断流，防止雪崩</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏没有，也不需要这种概念，游戏请求不会突然升高，即便有，也通过GM后台人为控制</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">断流器中间件 </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">服务发现</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">如何找到服务器地址。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">服务有变化时，通过Watch系统通知订阅者更新本地缓存</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">服务器没有变化时，使用本地缓存找到服务地址</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">游戏服务器互相依赖复用只在很小的范围内，因此无需在不同语言不同进程服务间获得地址，大部分在配置文件中填写各服务的IP及地址即可互相访问。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">早期游戏自己编写服务器状态及地址发现服务。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">有用redis做服务发现</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">使用服务发现系统，分布式部署。无需依赖配置文件</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333; font-weight: bold;">网关需求</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Game:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">网关处理客户端上下线通知，心跳，维持连接，转发，广播上下行封包</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">Web:</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">根据请求地址路由，无上下线概念，无心跳。广播通过消息推送系统完成</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;"> </span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">由于笔者从事游戏行业，对Web服务器概念在逐渐熟悉中，若有错误和不足请各位大佬指出。</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><span style="font-size: 16px; color: #333333;">本人新书《Go语言从入门到进阶实战》，生动的语言，例子带有各种彩蛋，轻松了解Go语言特性，更有</span><a href="https://github.com/davyxu/cellnet"><span style="font-size: 16px; color: #003884;">cellnet</span></a><span style="font-size: 16px; color: #333333;">框架剖析解密</span></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"></div>
<div yne-bulb-block="paragraph" style="white-space: pre-wrap; line-height: 1.75;"><a href="https://search.jd.com/Search?keyword=go%E8%AF%AD%E8%A8%80%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E8%BF%9B%E9%98%B6%E5%AE%9E%E6%88%98&amp;enc=utf-8&amp;suggest=1.def.0.V02&amp;wq=Go%E8%AF%AD%E8%A8%80%E4%BB%8E&amp;pvid=145d55a92cab4b07b71326f8beb1700b"><span style="font-size: 16px; color: #003884;">https://search.jd.com/Search?keyword=go%E8%AF%AD%E8%A8%80%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E8%BF%9B%E9%98%B6%E5%AE%9E%E6%88%98&amp;enc=utf-8&amp;suggest=1.def.0.V02&amp;wq=Go%E8%AF%AD%E8%A8%80%E4%BB%8E&amp;pvid=145d55a92cab4b07b71326f8beb1700b</span></a></div>
<img src ="http://www.cppblog.com/sunicdavy/aggbug/215887.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2018-08-29 11:16 <a href="http://www.cppblog.com/sunicdavy/archive/2018/08/29/215887.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Golang 热更新研究笔记</title><link>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 06 Jul 2017 04:47:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/215057.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/215057.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/215057.html</trackback:ping><description><![CDATA[<p data-source-line="1" style="box-sizing: border-box; margin-bottom: 16px; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff; margin-top: 0px !important;">本文主要研究游戏服务器带状态的热更新需求 http的无状态热更新需求已经有成熟方案, 故不在本文描述范围</p><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#基本概念" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>基本概念</h1><ul data-source-line="6" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">Golang的热更新采用什么机制?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">使用go1.8提供的plugin包机制实现</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">plugin包本身设计的目的是热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">plugin包其实只是支持将代码分别编译为多个动态库,动态加载后运行 并不能完全支持类似C/C++的动态库方式处理代码</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">带状态的进程热更新的基本概念及范围是什么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">数据部分(model)不更新, 只更新逻辑部分(函数)</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">表格和配置更新算热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">算, 但不是本文描述范围</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">热更新能在windows上使用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">不支持</p></li></ul><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#代码及结构" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>代码及结构</h1><ul data-source-line="29" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">我能将原来一个exe的代码编译为so提供给plugin使用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">可以, 但是必须仍然保留main包作为插件入口, 并在main包内添加提供给plugin调用入口.</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果动态库中没有main包, 编译出的so能用么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">不能, 包必须包含main, 否则输出的是.a的文件, plugin包加载会报错</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">动态库中, 非main包的的代码修改能做热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;"><span style="box-sizing: border-box; font-weight: 600;">不能</span>!(崩溃了吧, 我提了一个issue:&nbsp;<a href="https://github.com/golang/go/issues/20554" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none; background-color: transparent;">https://github.com/golang/go/issues/20554</a>)</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果确实做了修改, 底层会报错: plugin was built with a different version of package</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">解决方法: 修改plugin包底层实现并重新编译 打开runtime/plugin.go, 注释以下代码 for _, pkghash := range md.pkghashes { if pkghash.linktimehash != *pkghash.runtimehash { return "", nil, pkghash.modulename } } 执行/usr/local/go/run.bash 重编译+测试</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">代码中哪些可以被更新? 方法可以被更新么? 闭包呢?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">只能更新拥有静态地址的结构.例如: 包级别函数(类似于静态函数)</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">例如: svc_0.so里有一个Foo函数, svc_1.so修改了Foo函数实现, 热更新可实现</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;"><span style="box-sizing: border-box; font-weight: 600;">闭包=函数+捕获变量</span>, 实际上是一个动态结构, 没有静态地址, 无法被更新</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">各种包级别变量, 结构体变量, 结构体方法, 局部变量均不能被热更新, 但是变量值不会被影响</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">新增结构可以被运行</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">使用结构体方法调用了包级别函数, 包级别函数能被更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">可以, 虽然方法不能被更新, 但方法被调用的包级别函数的地址是固定的, 所以可以被热更新</p></li><li style="box-sizing: border-box; margin-top: 0.25em;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">init包初始化函数能用么? 能被热更新么?</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">官方这样描述:</p><pre data-source-line="71" style="box-sizing: border-box; font-stretch: normal; font-size: 11.9px; line-height: 1.45; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; word-wrap: normal; margin-top: 0px; margin-bottom: 16px; padding: 16px; overflow: auto; border-radius: 3px; background-color: #f7f7f7;"><code style="box-sizing: border-box; display: inline; overflow: visible; padding: 0px; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; margin: 0px; font-size: 11.9px; border-radius: 3px; word-break: normal; border: 0px; line-height: inherit; word-wrap: normal; background: 0px 0px transparent;"><span style="box-sizing: border-box; font-weight: 700;">When</span> a plugin <span style="box-sizing: border-box; font-weight: 700;">is</span> first opened, the init functions <span style="box-sizing: border-box; font-weight: 700;">of</span> <span style="box-sizing: border-box; font-weight: 700;">all</span> packages <span style="box-sizing: border-box; font-weight: 700;">not</span> already part <span style="box-sizing: border-box; font-weight: 700;">of</span> the program are called. The main <span style="box-sizing: border-box; font-weight: 700;">function</span> <span style="box-sizing: border-box; font-weight: 700;">is</span> <span style="box-sizing: border-box; font-weight: 700;">not</span> run. A plugin <span style="box-sizing: border-box; font-weight: 700;">is</span> only initialized once, <span style="box-sizing: border-box; font-weight: 700;">and</span> cannot be closed</code></pre><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">插件第一次被打开时, 其关联的, 没有成为程序的一部分的所有的包的init函数将被调用. 插件的main函数不会被调用. 插件只会被初始化一次, 不能被关闭</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">因此, 需要手动将init函数改成自己的函数, 统一在so的main包里调用</p></li></ul><h1><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#编译" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>编译</h1><ul data-source-line="80" style="box-sizing: border-box; margin-top: 0px; padding-left: 2em; color: #333333; font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 21px; widows: 1; background-color: #ffffff; margin-bottom: 0px !important;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如何编译获得plugin包支持的动态库</p><pre data-source-line="82" style="box-sizing: border-box; font-stretch: normal; font-size: 11.9px; line-height: 1.45; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; word-wrap: normal; margin-top: 0px; margin-bottom: 16px; padding: 16px; overflow: auto; border-radius: 3px; background-color: #f7f7f7;"><code style="box-sizing: border-box; display: inline; overflow: visible; padding: 0px; font-family: Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; margin: 0px; font-size: 11.9px; border-radius: 3px; word-break: normal; border: 0px; line-height: inherit; word-wrap: normal; background: 0px 0px transparent;">SVCNAME=<span style="box-sizing: border-box; color: teal;">$1</span> SVCVER=<span style="box-sizing: border-box; color: teal;">$2</span> TIMESTAMP=`date <span style="box-sizing: border-box; color: #dd1144;">'+%Y%m%d_%H%M%S'</span>` go build -v -buildmode=plugin --ldflags=<span style="box-sizing: border-box; color: #dd1144;">"-pluginpath=${SVCNAME}_${TIMESTAMP}"</span> -o ${SVCNAME}<span style="box-sizing: border-box; color: teal;">_</span>${SVCVER}.so ${SVCNAME}</code></pre><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">-buildmode=plugin是重要参数</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">--ldflags里的-pluginpath的作用是: 每次编译的内部识别路径都是不同的, 避免重复加载的警告</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">参考:&nbsp;<a href="https://github.com/golang/go/issues/19004" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none; background-color: transparent;">https://github.com/golang/go/issues/19004</a></p></li></ul><img src ="http://www.cppblog.com/sunicdavy/aggbug/215057.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2017-07-06 12:47 <a href="http://www.cppblog.com/sunicdavy/archive/2017/07/06/215057.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MMO相位技术研究</title><link>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Sat, 08 Apr 2017 06:41:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/214817.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/214817.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/214817.html</trackback:ping><description><![CDATA[<h1>相位技术</h1><p data-source-line="3" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位技术大规模出现在魔兽世界WLK版本, 现在应用已经广泛应用在各种MMORPG游戏中. 下面对相位技术的做法进行简单归纳汇总</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#表现分类" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>表现分类</h2><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#副本相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>副本相位</h3><p data-source-line="10" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">早期副本的出现, 避免抢怪问题. 所以, 副本其实本身就是一种相位技术. 只不过实现时, 我们一般会将小队和怪物直接预分配在独立的一个副本实例中(所以副本原文也是实例的意思)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#分线相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>分线相位</h3><p data-source-line="15" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位技术还没有正式命名时, 同一个场景, 玩家进到不同的分线看到的玩家不一样, 也是属于相位的一种. 当然, 如果是组队玩家, 服务器默认会分配所有队伍玩家在同一个线(位面)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#真相位" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>真相位</h3><p data-source-line="20" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">副本相位和分线相位其实都是静态相位, 一旦进入, 中途不会有切换或者混合查看的过程. 真相位可以在一个场景中,动态切换相位, 相位内和相位外所以不同</p><p data-source-line="22" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">我们常见的真相位表现为:&nbsp;<span style="box-sizing: border-box; font-weight: bolder;">相位中的角色+玩家+队伍成员</span></p><p data-source-line="24" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">在护送任务时, 还会在上面所见角色中叠加世界中的所有角色, 也就是说, 你和队伍成员可以看到的角色, 其他人看不到, 其他人也看不到你和你的队伍成员</p><hr style="box-sizing: content-box; overflow: hidden; height: 4px; padding: 0px; margin: 16px 0px; border-width: 0px; border-style: initial; border-bottom-color: #eeeeee; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background: #e7e7e7;" /><p data-source-line="28" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">为了清晰的简单的描述, 我为相位创建如下概念与名词</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#相位客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>相位客体</h2><p data-source-line="33" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">表现为除玩家外的角色(怪物,交互物体与相位可见场景)</p><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#私有客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>私有客体</h3><p data-source-line="37" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">这是最常见的一种相位内角色</p><ul data-source-line="39" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">取PhasingID时,为PhasingTargetID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">生成规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">当玩家开启相位后, 在玩家相位内<span style="box-sizing: border-box; font-weight: bolder;">生成的角色</span>为私有客体.</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">此时, 将 PhasingTargetID设置为相位生成者的实例ID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">删除规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">如果玩家退出相位, 私有客体会存在一段时间或按照需求删除</p></li></ul><h3><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#公共客体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>公共客体</h3><p data-source-line="55" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">一般指提前放置在场景中, 世界内不可见, 但是能被同相位玩家可见,且同相位玩家都可以互相可见 比如: 只要接了同一个任务的玩家, 都可以看到的NPC</p><ul data-source-line="58" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">取PhasingID时,为PublicPhasingID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">生成规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">通过场景编辑器, 放置角色时, 设置其可被观察到的任务ID</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">角色被加载后, 将任务ID设置到StaticPhasingID</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">删除规则</p><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">场景删除, 角色删除</p></li></ul><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#相位主体" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>相位主体</h2><p data-source-line="75" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">包含玩家与同队伍玩家</p><ul data-source-line="78" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;"><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">开启相位后, 可见私有客体+公有客体</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队长视为相位主体, 单人时, 自己为队长</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队伍其他成员共享队长的私有相位客体</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">队伍其他成员根据自己的PublicPhasingID匹配目标对象的PublicPhasingID时可互相可见</p></li><li style="box-sizing: border-box;"><p style="box-sizing: border-box; margin-top: 16px; margin-bottom: 16px;">持有变量</p></li></ul><p data-source-line="88" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位开启时, 取PhasingID时, 为角色实例ID</p><p data-source-line="90" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">相位关闭时, 取PhasingID时, 为0</p><p data-source-line="92" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">PublicPhasingID</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#可见规则" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>可见规则</h2><p data-source-line="98" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">当两个角色的PhasingID相等时, 主体与私有客体互相可见</p><p data-source-line="100" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">当两个角色的PublicPhasingID相等时, 主体与公有客体互相可见</p><p data-source-line="102" style="box-sizing: border-box; margin-top: 0px; margin-bottom: 16px; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff;">可以通过开关设置, 是否在可见的相位客体基础上, 叠加世界角色(护送任务)</p><h2><a href="file:///C:/Users/Davy/AppData/Local/Youdao/YNote/markdown/index.html#约束" style="box-sizing: border-box; color: #4078c0; text-decoration-line: none;"></a>约束</h2><ul data-source-line="106" style="box-sizing: border-box; margin-top: 0px; padding-left: 2em; color: #333333; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Segoe UI&quot;, Arial, freesans, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; line-height: 22.4px; widows: 1; background-color: #ffffff; margin-bottom: 0px !important;"><li style="box-sizing: border-box;">玩家同时只能看见1个相位</li></ul><img src ="http://www.cppblog.com/sunicdavy/aggbug/214817.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2017-04-08 14:41 <a href="http://www.cppblog.com/sunicdavy/archive/2017/04/08/214817.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Golang的简单反射性能测试</title><link>http://www.cppblog.com/sunicdavy/archive/2016/08/12/214152.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 12 Aug 2016 07:26:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/08/12/214152.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/214152.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/08/12/214152.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/214152.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/214152.html</trackback:ping><description><![CDATA[<h3>测试用例</h3> <p>我们对Golang的结构体变量赋值, 以及单参数函数调用进行反射和native操作的测试<pre><p><p><code>&nbsp;</code></p><p><code>package main</code></p><p><code>&nbsp;</code></p><p><code>import (</code></p><p><code>    "reflect"</code></p><p><code>    "testing"</code></p><p><code>)</code></p><p><code>&nbsp;</code></p><p><code>type data struct {</code></p><p><code>    Hp int</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>const AssignTimes = 100000000</code></p><p><code>&nbsp;</code></p><p><code>func TestNativeAssign(t *testing.T) {</code></p><p><code>&nbsp;</code></p><p><code>    v := data{Hp: 2}</code></p><p><code>&nbsp;</code></p><p><code>    for i := 0; i &lt; AssignTimes; i++ {</code></p><p><code>        v.Hp = 3</code></p><p><code>    }</code></p><p><code>&nbsp;</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>func TestReflectAssign(t *testing.T) {</code></p><p><code>&nbsp;</code></p><p><code>    v := data{Hp: 2}</code></p><p><code>&nbsp;</code></p><p><code>    vv := reflect.ValueOf(&amp;v).Elem()</code></p><p><code>&nbsp;</code></p><p><code>    f := vv.FieldByName("Hp")</code></p><p><code>&nbsp;</code></p><p><code>    for i := 0; i &lt; AssignTimes; i++ {</code></p><p><code>&nbsp;</code></p><p><code>        f.SetInt(3)</code></p><p><code>    }</code></p><p><code>&nbsp;</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>func TestReflectFindFieldAndAssign(t *testing.T) {</code></p><p><code>&nbsp;</code></p><p><code>    v := data{Hp: 2}</code></p><p><code>&nbsp;</code></p><p><code>    vv := reflect.ValueOf(&amp;v).Elem()</code></p><p><code>&nbsp;</code></p><p><code>    for i := 0; i &lt; AssignTimes; i++ {</code></p><p><code>&nbsp;</code></p><p><code>        vv.FieldByName("Hp").SetInt(3)</code></p><p><code>    }</code></p><p><code>&nbsp;</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>func foo(v int) {</code></p><p><code>&nbsp;</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>const CallTimes = 100000000</code></p><p><code>&nbsp;</code></p><p><code>func TestNativeCall(t *testing.T) {</code></p><p><code>    for i := 0; i &lt; CallTimes; i++ {</code></p><p><code>&nbsp;</code></p><p><code>        foo(i)</code></p><p><code>    }</code></p><p><code>}</code></p><p><code>&nbsp;</code></p><p><code>func TestReflectCall(t *testing.T) {</code></p><p><code>&nbsp;</code></p><p><code>    v := reflect.ValueOf(foo)</code></p><p><code>&nbsp;</code></p><p><code>    for i := 0; i &lt; CallTimes; i++ {</code></p><p><code>&nbsp;</code></p><p><code>        v.Call([]reflect.Value{reflect.ValueOf(2)})</code></p><p><code>    }</code></p><p><code>}</code></p></pre>
<h3>性能测试数据</h3>
<p>=== RUN TestNativeAssign<br>— PASS: TestNativeAssign (0.03s)<br>=== RUN TestReflectAssign<br>— PASS: TestReflectAssign (0.41s)<br>=== RUN TestReflectFindFieldAndAssign<br>— PASS: TestReflectFindFieldAndAssign (9.86s)<br>=== RUN TestNativeCall<br>— PASS: TestNativeCall (0.03s)<br>=== RUN TestReflectCall<br>— PASS: TestReflectCall (21.46s)
<h3>测试评测</h3>
<ul>
<li>在结构体变量赋值测试用例中, 我们发现TestReflectFindFieldAndAssign赋值格外的耗时. 分析性能点在FieldByName这个函数上, 我们查了下底层如何实现的:</li></ul><pre><p><p><code>// FieldByName returns the struct field with the given name</code></p><p><code>// and a boolean to indicate if the field was found.</code></p><p><code>func (t *structType) FieldByName(name string) (f StructField, present bool) {</code></p><p><code>    // Quick check for top-level name, or struct without anonymous fields.</code></p><p><code>    hasAnon := false</code></p><p><code>    if name != "" {</code></p><p><code>        for i := range t.fields {</code></p><p><code>            tf := &amp;t.fields[i]</code></p><p><code>            if tf.name == nil {</code></p><p><code>                hasAnon = true</code></p><p><code>                continue</code></p><p><code>            }</code></p><p><code>            if *tf.name == name {</code></p><p><code>                return t.Field(i), true</code></p><p><code>            }</code></p><p><code>        }</code></p><p><code>    }</code></p><p><code>    if !hasAnon {</code></p><p><code>        return</code></p><p><code>    }</code></p><p><code>    return t.FieldByNameFunc(func(s string) bool { return s == name })</code></p><p><code>}</code></p></pre>
<p>各位看官必须吐槽用for来遍历获取数据, 但冷静下来分析. 这样做无可厚非.<br>试想如果reflect包在我们使用ValueOf时使用map缓冲好一个结构体所有字段的访问数据后, 肯定访问指定字段速度会很快<br>但是, 以空间换速度的需求其实最多满足了1%的需求.<br>同样的例子是图形API里访问Shader变量的方法, 总是默认使用字符串获取, 速度很慢. 当你想快速访问时, 请提前按需缓存字段<br>那么, Golang使用的也是这样的思路. 虽然暴力了一点, 但是能够让程序跑对, 性能优化的东西放在之后来做, 缓冲下就可以解决
<ul>
<li>在调用测试用例中, 毫无悬念的, 调用速度很慢<br>因此, 我们在平时使用反射时, 尽量偏向于反射变量缓冲存在下的变量赋值或者获取<br>而调用的需求尽量减少, 如果有goroutine存在的情况下, 则不必太多担心.</li></ul><img src ="http://www.cppblog.com/sunicdavy/aggbug/214152.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-08-12 15:26 <a href="http://www.cppblog.com/sunicdavy/archive/2016/08/12/214152.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>服务器开发语言比较</title><link>http://www.cppblog.com/sunicdavy/archive/2016/01/05/212611.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 05 Jan 2016 08:51:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2016/01/05/212611.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/212611.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2016/01/05/212611.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/212611.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/212611.html</trackback:ping><description><![CDATA[<p>以下比较的基础都是基于一种编程语言+一定的第三方或者自己编写的网络库和底层进行的，Skynet稍微特殊，但总体比较合适放到比较中来</p> <h1>C#</h1> <p>开发效率：Windows下可以通过VisualStudio进行开发，其他平台可以使用MonoDevelop，非常方便</p> <p>运行效率：JIT的性能优化比较到位，能适应90%性能环境</p> <p>部署便捷性：可以通过交叉编译生成其他平台的可执行文件，通过mono运行可执行文件</p> <p>调试便捷性：VisualStudio和MonoDevelop调试均很方便， 还可远程调试</p> <p>上手度：对C系语言熟悉的几天就可上手</p> <p>热更新：可以通过DLL方式进行</p> <p>Web对接：可做，代码比较啰嗦</p> <p>崩溃处理：可通过try catch捕获错误</p> <p>网络库编写难度：一般，需注意gc问题</p> <p>第三方网络库及框架数量：一般</p> <p>&nbsp;</p> <h1>Golang</h1> <p>开发效率：高</p> <p>运行效率：并发上非常有优势，对CPU利用率比较高，原生运行无虚拟机</p> <p>部署便捷性：一次编译到处运行，无任何运行库依赖</p> <p>调试便捷性：实际操作中，单线程挂接调试器可行， 但变量显示不正确，开发期基本采用日志方式进行查错</p> <p>上手度：语言简单，特性少， 新手1周能贡献代码</p> <p>热更新：无法进行热更新，语言无法编译为DLL，也不支持DLL加载（linux平台的.so加载忽略不计）</p> <p>Web对接：非常方便， 代码精简</p> <p>崩溃处理：崩溃后以命令行方式打印出栈，程序内可以捕获任何崩溃错误并继续运行</p> <p>网络库编写难度：简单，比C socket更简单</p> <p>第三方网络库及框架数量：偏少</p> <p>&nbsp;</p> <h1>Skynet(lua+C)</h1> <p>开发效率：基于动态语言的开发初次写比较快，后期维护和重构会耗费一定的时间在查错上</p> <p>运行效率：基于lua jit的运行效率还是能接受的</p> <p>部署便捷性：方便， 只有底层修改需要重新编译， 大部分时间只用更新lua文件</p> <p>调试便捷性：不是很方便，基于日志方式进行查错</p> <p>上手度：lua语言特性有部分和C系语言有一定差异，基于Actor模型的思想学习，适应需要耗费一定的时间</p> <p>热更新：类似于Erlang，可精确到函数级的热更新</p> <p>Web对接：有一些http支持，通过社区慢慢进行完善</p> <p>崩溃处理：lua天生可以捕获错误</p> <p>网络库编写难度：自带，无需编写</p> <p>第三方网络库及框架数量：通过社区慢慢完善</p> <p>&nbsp;</p> <h1>C++</h1> <p>开发效率：编译慢，文件多，通用库少</p> <p>运行效率：native速度标杆</p> <p>部署便捷性：编写各类的make门槛较高</p> <p>调试便捷性：可通过VisualStudio进行Windows平台调试</p> <p>上手度：2~3年经验的熟手仍然会写出崩溃和泄露代码</p> <p>热更新：可通过DLL进行</p> <p>Web对接：代码啰嗦，第三方库少</p> <p>崩溃处理：Windows下可使用SEH捕获段异常，其他平台只能通过崩溃后进行coredump分析，容错非常差</p> <p>网络库编写难度：基于asio编写较为简单，但总体看来难度不低</p> <p>第三方网络库及框架数量：较多</p> <p>&nbsp;</p> <p>以下是得分</p> <p></td></tr><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/cce8cda86825_E2DC/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/cce8cda86825_E2DC/image_thumb.png" width="326" height="268"></a> <p>&nbsp; <p>从发文时的项目对这些语言使用率来说，Java，Erlang，C++编写的服务器较多，Golang，JavaScript，C#是第二梯队，Skynet由于上手不是很容易，所以仅有两位数的团队在使用，但总体表现还是比较出色的 <p>对于老团队， C++的服务器工具链和框架已经相对成熟， 完全没必要更换新语言， 只是在对接sdk感觉困难时，可以尝试Golang这些对web有优势的语言进行混合语言开发 <p>对于新团队，开发效率，上手度和部署效率是优先选择的，C#，Golang，JavaScript这些新兴语言会让你事半功倍 <p>对于大规模无需选服的服务器， Skynet的actor模型对扩展会比较容易 <p>对于大公司，好项目，上线后需要通过热更新进行bug修补的，C#，C++，Erlang会是首选 <p>&nbsp; <p>但总的一点， 还是根据团队熟悉度来选择语言，贸然的使用新语言的风险也是很大的 <img src ="http://www.cppblog.com/sunicdavy/aggbug/212611.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2016-01-05 16:51 <a href="http://www.cppblog.com/sunicdavy/archive/2016/01/05/212611.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>开源Golang游戏服务器框架cellnet</title><link>http://www.cppblog.com/sunicdavy/archive/2015/10/16/212026.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 16 Oct 2015 03:44:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/10/16/212026.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/212026.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/10/16/212026.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/212026.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/212026.html</trackback:ping><description><![CDATA[<p>简单,方便,高效的Go语言的游戏服务器框架</p> <div class="csharpcode"><pre class="alt">func server() {</pre><pre>&nbsp;</pre><pre class="alt">    pipe := cellnet.NewEventPipe()</pre><pre>&nbsp;</pre><pre class="alt">    evq := socket.NewAcceptor(pipe).Start(<span class="str">"127.0.0.1:7234"</span>)</pre><pre>&nbsp;</pre><pre class="alt">    socket.RegisterSessionMessage(evq, coredef.TestEchoACK{}, func(content <span class="kwrd">interface</span>{}, ses cellnet.Session) {</pre><pre>        msg := content.(*coredef.TestEchoACK)</pre><pre class="alt">&nbsp;</pre><pre>        log.Println(<span class="str">"server recv:"</span>, msg.String())</pre><pre class="alt">&nbsp;</pre><pre>        ses.Send(&amp;coredef.TestEchoACK{</pre><pre class="alt">            Content: proto.String(msg.String()),</pre><pre>        })</pre><pre class="alt">&nbsp;</pre><pre>    })</pre><pre class="alt">&nbsp;</pre><pre>    pipe.Start()</pre><pre class="alt">&nbsp;</pre><pre>}</pre><pre class="alt">&nbsp;</pre><pre>func client() {</pre><pre class="alt">&nbsp;</pre><pre>    pipe := cellnet.NewEventPipe()</pre><pre class="alt">&nbsp;</pre><pre>    evq := socket.NewConnector(pipe).Start(<span class="str">"127.0.0.1:7234"</span>)</pre><pre class="alt">&nbsp;</pre><pre>    socket.RegisterSessionMessage(evq, coredef.TestEchoACK{}, func(content <span class="kwrd">interface</span>{}, ses cellnet.Session) {</pre><pre class="alt">        msg := content.(*coredef.TestEchoACK)</pre><pre>&nbsp;</pre><pre class="alt">        log.Println(<span class="str">"client recv:"</span>, msg.String())</pre><pre>&nbsp;</pre><pre class="alt">    })</pre><pre>&nbsp;</pre><pre class="alt">    socket.RegisterSessionMessage(evq, coredef.SessionConnected{}, func(content <span class="kwrd">interface</span>{}, ses cellnet.Session) {</pre><pre>&nbsp;</pre><pre class="alt">        ses.Send(&amp;coredef.TestEchoACK{</pre><pre>            Content: proto.String(<span class="str">"hello"</span>),</pre><pre class="alt">        })</pre><pre>&nbsp;</pre><pre class="alt">    })</pre><pre>&nbsp;</pre><pre class="alt">    pipe.Start()</pre><pre>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>项目地址: <a title="https://github.com/davyxu/cellnet" href="https://github.com/davyxu/cellnet">https://github.com/davyxu/cellnet</a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/212026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-10-16 11:44 <a href="http://www.cppblog.com/sunicdavy/archive/2015/10/16/212026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>pp助手服务器端支付的RSA的奇葩公钥解密设计</title><link>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 12 Oct 2015 06:27:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/211993.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/211993.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/211993.html</trackback:ping><description><![CDATA[<p>最近接入pp助手的服务器端支付, 按照PP官方提供的文档来看, 需要服务器做RSA的验证. </p> <p>首先我们来看下</p> <h1>RSA的几个标准用法</h1> <h2>非对称加密解密</h2> <p>假设A要把内容传输给B</p> <p>1. B生成RSA的公钥和密钥, 这是成对出现的, 密钥由B保存, 把公钥告诉A</p> <p>2. A用B的公钥加密内容, 并把密文内容传输给B</p> <p>3. B用密钥解密</p> <h2>验证</h2> <p>证明某个内容是你发的, 而不是被别人冒名顶替, 例如git的push中就带有这个功能</p> <p>假设A有内容,&nbsp; B要验证内容确实由A发出</p> <p>1. A生成公钥和密钥</p> <p>2. A将内容做一个hash, 把hash码用自己的密钥加密并把这段密文发给B</p> <p>3. B用A的公钥对密文进行验证, 即可确认密文是否由A发出</p> <p>&nbsp;</p> <p>可以看出, 两种用法都是典型的非对称用法</p> <p>但PP助手却干了件神奇的事情:</p> <h1>非对称当对称算法加解密</h1> <p>在PP SDK官方文档里, 我们找到了PHP语言的验证方法, 方法里使用了这样一个API</p> <p><a href="http://php.net/manual/zh/function.openssl-public-decrypt.php">openssl_public_decrypt</a></p> <p>从官方文档看得出这个使用openssl的算法库</p> <p>&nbsp;</p> <p>类似的, 还有Java, C++, Python语言的处理方法</p> <p>其中, C++也是用的openssl, Python则是需要预编译C库，在Ubuntu下需要手工patch M2Crypto的_ssl.c文件.</p> <p>&nbsp;</p> <p>先不说这些非正规的编译,patch方法会造成多大的问题, 单就这个用公钥解密就很蛋疼</p> <p>从之前的RSA算法中了解, 只有对公钥进行验证的方法, 也就是只能得到是还是不是的结果. 但PP的SDK则要求必须用公钥解密…</p> <p>解出的数据为一段json, 以对比是否有订单篡改.</p> <p>&nbsp;</p> <p>那么这种做法就等效于, 用最简单的异或+一个公钥进行订单加密, 然后同样用这个公钥进行解密</p> <p>只不过用RSA感觉很高级…</p> <p>这种做法一旦公钥在PP助手服务器或者玩家的开发服务器, 甚至源代码泄露, 那么马上就有很大的伪造订单的危险</p> <p>&nbsp;</p> <p>我把这个做法发给朋友看, 他们说, 其实PP助手的开发者只管用了RSA, 跟传输不是明文就好了, 至于什么信息安全, 都是屁!</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/211993.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-10-12 14:27 <a href="http://www.cppblog.com/sunicdavy/archive/2015/10/12/211993.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对golang服务器开发模式的一些思考</title><link>http://www.cppblog.com/sunicdavy/archive/2015/09/09/211784.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 09 Sep 2015 11:06:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/09/09/211784.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/211784.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/09/09/211784.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/211784.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/211784.html</trackback:ping><description><![CDATA[<h1>多线程+同步阻塞模型</h1> <p>在我们的游戏项目中使用的golang服务器开发方式如下</p> <p>1.多线程逻辑</p> <p>2.同步阻塞. 也就是说, 每个人一个线程(goroutine), io线程=逻辑线程</p> <p>这种方式的优点:</p> <p>1. 同步阻塞方式与人的思维方式类同</p> <p>2. 逻辑处理性能有一定提升</p> <p>在大规模使用这种模式编写逻辑后, 我们发现了这种模式只有1个缺点: <strong>编写者需要处理多线程关系</strong></p> <p>但这本身确实直接致命的, 回想C++时代, 多线程处理时, 调试重现的困难… 脑补景象太惨不敢直视</p> <h1>单线程+异步多进程模型</h1> <p>在C++时代, 我曾经编写过一套asio的C++服务器框架. 采用io多线程, 逻辑单线程, 依赖着C++高性能的优势, 让开发便捷简单且无需关心线程问题.</p> <p>那么到了golang时代, 为什么不能试下单线程异步多进程方式来编写逻辑?</p> <p>与多线程同步阻塞对比后, 我们发现, 两者优缺点互补. 那这就回到了领域选型问题了. 对于游戏服务器需要的上手简单, 开发便捷, 压力降低(非MMO)这些特点来说, 单线程异步多进程再合适不过了</p> <p>那么, 我们在用golang编写单线程异步多进程服务器应该注意哪些点呢?</p> <p>1. socket处理完全封装, 只通过channel抛出到逻辑线程排队处理</p> <p>2. 数据库, rpc及其他io处理, 一律改为异步回调模式, 不使用同步接口</p> <p>3. 玩家存盘提交数据可以考虑复制并提交到存盘线程方式, 提高性能. </p> <p>4. 采用多进程架构, 比如设网关进程, 把io压力分散到进程中</p> <p>5. 逻辑编写中, 不允许使用go开线程及channel, 有需要提高性能部分需要单独编写</p> <p>&nbsp;</p> <h1>Actor模型的痛</h1> <p>cellnet在开发时本来考虑使用actor模型来进一步简化多线程逻辑的麻烦, 经历了一段时间的原型开发后, 发现了一些问题, 列举如下:</p> <p>1. golang的强类型不适合actor模型这种经常需要动态生成各类消息的模型, 但skynet(C+lua)/erlang就有天生优势</p> <p>2. actor模型本身不是万能的, 不能解决所有需求, 特别是游戏</p> <p>3. actor模型理解到应用有一定的难度. 本身还需要搭建框架, 上手复杂</p> <p>总之, 看过一些erlang及skynet的用例, 没有应用的很纯正且成熟的成功actor模型案例, 从传统socket服务器框架跨越到actor模型会扯到蛋, 因此, 后期cellnet会考虑回归到成熟的socket服务器框架. 把架构做到简单上手, 高扩展上.</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/211784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-09-09 19:06 <a href="http://www.cppblog.com/sunicdavy/archive/2015/09/09/211784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大服务器架构讨论</title><link>http://www.cppblog.com/sunicdavy/archive/2015/07/21/211321.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 21 Jul 2015 02:30:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/07/21/211321.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/211321.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/07/21/211321.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/211321.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/211321.html</trackback:ping><description><![CDATA[<p>最近参加了一个大服务器架构讨论活动, 记录下心得 <h1>概述</h1> <p>游戏客户端采用Cocos2dx-Lua的纯Lua编写逻辑, 服务器采用Golang作为开发语言 <p>游戏类型类似于COC,因此无需选服. 需要使用大服务器架构进行处理 <h1><b>数据库</b></h1> <p>采用Mongodb做持久存储, redis做跨服通信数据交换 <p>使用UCloud的云技术, 省去了烦人的运维工作 <h1><b>通信及协议</b></h1> <p>客户端和服务器通讯使用HTTP短连接, 基于json的数据封包协议 <p>服务器间大量使用Golang自带的json+rpc进行通信 <h1><b>服务器类型</b></h1> <p>服务器类型大致分为逻辑服务器,战斗服务器, 中心服务器 <h2><b>逻辑服务器</b></h2> <p>逻辑服务器负责日常逻辑及公共逻辑处理(好友, 公会) <p>1个逻辑服务器对应一个区, n个区均使用Ucloud云Mongodb进行数据存储 <h2><b>战斗服务器</b></h2> <p>战斗服务器是一个集群, 集群会返回一个负载最低的服务器返回使用 <p>战斗服务器通过cgo技术与客户端C++/lua的战斗逻辑进行逻辑复用, 在此技术上进行 <p>战斗逻辑的校验 <h2><b>中心服务器</b></h2> <p>客户端登陆前, 在中心服务器这里获得可登陆的逻辑服务器地址, 同时做一个负载均衡 <p>短连接 <h1><b>评价</b></h1> <p>由于操作系统的技术趋于稳定, 同时, 手游的弱交互型导致的游戏架构趋于简单. 因此网络负载不再是游戏服务器技术的瓶颈. 从经验看来, 游戏服务器技术, 更重要的是还是看数据库的选型及处理方式.&nbsp; <p>虽然Mongodb的性能上不如内存数据库. 但是从存储安全性上要比个人搭建的内存数据库简单, 安全 <p>外加上云技术的引用, 性能的瓶颈和运维的技术复杂度迎刃而解 <p>Redis用于跨服数据交互那是再好不过的数据中介了, 保证速度和稳定性, 绝对不是造轮子能比拟的 <p>短连接在手游上处理起来比长连接简单一些, 无需做断线重连. 服务器的底层也是由Golang的框架库保证质量的. 因此负载毫无问题. 服务器对内及对外均使用json进行数据交换, 简化了协议处理. 也方便了调试 <p>json rpc的性能损耗对于整个逻辑的处理来说均可以忽略不计</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/211321.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-07-21 10:30 <a href="http://www.cppblog.com/sunicdavy/archive/2015/07/21/211321.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>游戏数据库选型mysql,mongo, redis, memcached</title><link>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 19 Jun 2015 08:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/210992.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/210992.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/210992.html</trackback:ping><description><![CDATA[<h1>数据库选择历程</h1> <p>我们的项目一直使用MySQL作为数据库. 无论是从C++的服务器, 还是到Golang服务器. 当年搞服务器时, 看大部分人都是用SQL(MySQL/SQLServer), 而Mongo感觉像邪教一样, 再加上服务器还是Linux比较正统, 所以果断选了MySQL.</p> <p>刚开始感觉,游戏服务器的数据存储其实应该是蛮神圣的过程. 那么多的数据, 需要按照MySQL一样分表, 分字段存储, 为了查询, 还要乖乖的学一下SQL的语法</p> <p>就这么折腾了几年. 在云DB的蒙蔽下, 一直认为MySQL就是做游戏服务器存储的专业技术. 分布式和存储压力一定交给云DB来做. 直到真正试了下NoSQL在游戏服务器开发里的思路.</p> <p>用了Golang, 才发现同步写逻辑是多么的优雅. </p> <p>用了NoSQL系列的数据库, 才意识到: 游戏服务器的数据存储和游戏服务器的存盘两个概念差异其实蛮大的.</p> <p>MySQL中, 背包其实跟角色完全没有关系, 只是通过1个角色id映射过去, 人为的割裂了数据的关联性. 还硬生生的整出个概念叫结构化查询让你学</p> <p>NoSQL中, 只是把数据库当成是存储点, 每个角色的数据是完整的一块. 里面怎么存随你便. 每个角色通过id来查询, 其他都没有了</p> <p>于是乎, 游戏开发变得异常简单. MySQL角色进门查询4~5次才能搞定要的数据.而NoSQL一口气全查出来, 存盘也无需增量, 直接存盘就可以了</p> <p>所以现在觉得, NoSQL的思路对于游戏服务器存储来说简直是完美的!</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h1>NoSQL数据库方案对比</h1> <p>NoSQL下实现方案很多, 游戏常用的就这么3家: mongo, redis, memcached</p> <p>下面说下优缺点</p> <h2>mongo</h2> <p>磁盘映射内存数据库</p> <p>value为document类型, 基于BSON的value序列化</p> <p>应用场景:</p> <p>适合多写少读, 例如日志和备份</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h2>redis</h2> <p>内存数据库</p> <p>单核</p> <p>value限制512M</p> <p>多种value类型, 游戏用途使用私有的序列化协议(例如protobuf)</p> <p>支持落地(bgsave)</p> <p>用户: 新浪, 淘宝, Flickr, Github</p> <p>应用场景: 适合读写都很高, 数据处理复杂等</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>&nbsp;</p> <h2>memcached</h2> <p>内存数据库</p> <p>多核</p> <p>value限制1M</p> <p>不支持落地(持久化)</p> <p>用户: LiveJournal、hatena、Facebook、Vox</p> <p>应用场景: 动态系统中的缓冲, 适合多读少写</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <h1>个人评价</h1> <p>memcached 适合网页缓冲, 游戏里很少有使用. 目前只有腾讯云支持云memcached</p> <p>redis非常适合游戏的内存数据库, 但是落地策略会比较复杂, 需要具体分析, 可以参考后面的链接看下云风怎么处理这个问题</p> <p>mongo数据库在早期还是非常不错的NoSQL的数据库. 工具比较方便, 可视化. 但是随着近年来游戏的并发度越来越高, 所以为了一次到位, 很多人还是选择了redis</p> <p>下图参考自知乎问题. 链接在后面有提示, 若侵权请联系删除</p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/857198a996df_9ADD/image_5.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/857198a996df_9ADD/image_thumb_1.png" width="591" height="168"></a></p> <h1><strong>参考链接:</strong></h1> <h5><font style="font-weight: normal">&nbsp;&nbsp;&nbsp; 谈谈陌陌争霸在数据库方面踩过的坑( Redis 篇)</font></h5> <p><a title="http://blog.codingnow.com/2014/03/mmzb_redis.html" href="http://blog.codingnow.com/2014/03/mmzb_redis.html">http://blog.codingnow.com/2014/03/mmzb_redis.html</a></p> <p><font color="#ffffff">转载请注明: 战魂小筑</font><a href="http://www.cppblog.com/sunicdavy"><font color="#ffffff">http://www.cppblog.com/sunicdavy</font></a></p> <p>Memcache,Redis,MongoDB（数据缓存系统）方案对比与分析</p> <p><a title="http://blog.csdn.net/suifeng3051/article/details/23739295" href="http://blog.csdn.net/suifeng3051/article/details/23739295">http://blog.csdn.net/suifeng3051/article/details/23739295</a></p> <p>&nbsp;</p> <p><a title="http://www.zhihu.com/question/31417262" href="http://www.zhihu.com/question/31417262">http://www.zhihu.com/question/31417262</a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/210992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-06-19 16:23 <a href="http://www.cppblog.com/sunicdavy/archive/2015/06/19/210992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>golang的一个线程调度被停止的问题处理</title><link>http://www.cppblog.com/sunicdavy/archive/2015/01/30/209677.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 30 Jan 2015 08:25:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2015/01/30/209677.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/209677.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2015/01/30/209677.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/209677.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/209677.html</trackback:ping><description><![CDATA[<p>最近发现, golang写的游戏服务器, 在非调试状态下, 一切正常, 但是在挂接gdb调试时, 无法收到网络消息. 打了很多日志, 发现, 只要有goroutine的地方, 都没有切换进入. </p> <p>回想了下, goroutine的调度规则: 1.4之前, 在碰到syscall时, goroutine会被调度并处理. 1.4后, 只要有函数调用时, 均会进行一次调度. 密度比以前增加了, 更加接近真线程的处理. </p> <p>根据这个原理, 问题应该出现在服务器底层没有给系统提供调度机会的点上. 我们的服务器通过一个bool型的chan进行阻塞, 让服务器维持阻塞进行消息处理不退出. 但是最近为了在windows下提供命令行支持, 增加了一些代码, 如下</p> <div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>func WaitForExit() {</pre><pre><span class="lnum">   2:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">if</span> len(peerMap) == 0 {</pre><pre><span class="lnum">   4:  </span>        log.Println(<span class="str">"no peer running, exit!"</span>)</pre><pre class="alt"><span class="lnum">   5:  </span>        <span class="kwrd">return</span></pre><pre><span class="lnum">   6:  </span>    }</pre><pre class="alt"><span class="lnum">   7:  </span>&nbsp;</pre><pre><span class="lnum">   8:  </span>    <span class="rem">// 命令行功能只在windows下启用</span></pre><pre class="alt"><span class="lnum">   9:  </span>    <span class="kwrd">if</span> runtime.GOOS == <span class="str">"windows"</span> {</pre><pre><span class="lnum">  10:  </span>        reader := bufio.NewReader(os.Stdin)</pre><pre class="alt"><span class="lnum">  11:  </span>&nbsp;</pre><pre><span class="lnum">  12:  </span>        var running <span class="kwrd">bool</span> = <span class="kwrd">true</span></pre><pre class="alt"><span class="lnum">  13:  </span>&nbsp;</pre><pre><span class="lnum">  14:  </span>        go func() {</pre><pre class="alt"><span class="lnum">  15:  </span>            select {</pre><pre><span class="lnum">  16:  </span>            <span class="kwrd">case</span> &lt;-exitChan:</pre><pre class="alt"><span class="lnum">  17:  </span>                running = <span class="kwrd">false</span></pre><pre><span class="lnum">  18:  </span>            }</pre><pre class="alt"><span class="lnum">  19:  </span>        }()</pre><pre><span class="lnum">  20:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  21:  </span>        <span class="kwrd">for</span> running {</pre><pre><span class="lnum">  22:  </span>            data, _, _ := reader.ReadLine()</pre><pre class="alt"><span class="lnum">  23:  </span>            command := <span class="kwrd">string</span>(data)</pre><pre><span class="lnum">  24:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  25:  </span>            dispatchConsoleCommand(command)</pre><pre><span class="lnum">  26:  </span>        }</pre><pre class="alt"><span class="lnum">  27:  </span>    } <span class="kwrd">else</span> {</pre><pre><span class="lnum">  28:  </span>        <span class="rem">// Linux环境</span></pre><pre class="alt"><span class="lnum">  29:  </span>        &lt;-exitChan</pre><pre><span class="lnum">  30:  </span>    }</pre><pre class="alt"><span class="lnum">  31:  </span>&nbsp;</pre><pre><span class="lnum">  32:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>我暂时屏蔽了新加的这套功能, 维持&lt;-exitChan, 问题马上解决</p>
<p>结合前面的猜测, 我估计在reader.ReadLine()函数内, 没有给底层提供调度的机会, 导致其他goroutine无法运行, 造成服务器卡死</p>
<p>技术讨论群:&nbsp; 309800774 欢迎golang爱好者加入, 纯技术研讨</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/209677.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2015-01-30 16:25 <a href="http://www.cppblog.com/sunicdavy/archive/2015/01/30/209677.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++服务器架构机制设计总结</title><link>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 18 Dec 2014 08:39:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/209225.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/209225.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/209225.html</trackback:ping><description><![CDATA[<p>近期在写基于go的游戏服务器框架, 在全面脱离C/C++前, 需要对老架构进行一个总结  <p>基于C/C++游戏服务器框架总体设计的还是不错的, 兄弟们总体使用效果都是好评. 因为在技术上喜欢"偷懒", 所以在很多设计上, 都是力求简单, 高效(开发效率).  <p><strong>基于任务的异步DB查询系统, 带多重异步的同步</strong> <p>代码示例:  <div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>&nbsp;</pre><pre><span class="lnum">   2:  </span><span class="kwrd">void</span> BatchQueryPlayerInfo( uint32 ClientID, <span class="kwrd">const</span> std::<span class="kwrd">string</span>&amp; AccountName, int64 CharID )</pre><pre class="alt"><span class="lnum">   3:  </span>{</pre><pre><span class="lnum">   4:  </span>    GDBExecutor-&gt;Commit</pre><pre class="alt"><span class="lnum">   5:  </span>        (    </pre><pre><span class="lnum">   6:  </span>        dynamic_cast&lt;DBDataTask*&gt;( (<span class="kwrd">new</span> DBQueryCharInfo(  ClientID, CharID ) ) </pre><pre class="alt"><span class="lnum">   7:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryQuest( ClientID, CharID ) )</pre><pre><span class="lnum">   8:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQuerySkill( ClientID, CharID ) )</pre><pre class="alt"><span class="lnum">   9:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryHero( ClientID, CharID ) )</pre><pre><span class="lnum">  10:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryAccountInfo( ClientID, AccountName ) )</pre><pre class="alt"><span class="lnum">  11:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryEquip( ClientID, CharID ) )</pre><pre><span class="lnum">  12:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryObject( ClientID ,CharID ) )</pre><pre class="alt"><span class="lnum">  13:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryLevel(ClientID, CharID))</pre><pre><span class="lnum">  14:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryChapter(ClientID, CharID))</pre><pre class="alt"><span class="lnum">  15:  </span>        -&gt;LinkAtomTask( <span class="kwrd">new</span> DBQueryActivity( ClientID, CharID ))</pre><pre><span class="lnum">  16:  </span>        )</pre><pre class="alt"><span class="lnum">  17:  </span>        );</pre><pre><span class="lnum">  18:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  19:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>


<p>这段主要处理玩家在登陆时, 需要从DB查询大量的不同分类的数据. 为了保证效率, 我让每个Task并行执行, 然后通过一个机制, 让所有任务完成后, 回调第一个任务的一个函数. 这样就无需手动实现很多粘合代码, 避免了反复调试和错误</p>
<p><strong>基于protobuf反射机制的语句自动合成</strong></p>
<div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>DBUpdateCharInfo::DBUpdateCharInfo( int64 CharID, <span class="kwrd">const</span> std::<span class="kwrd">string</span>&amp; Buffer )</pre><pre><span class="lnum">   2:  </span>{</pre><pre class="alt"><span class="lnum">   3:  </span>    <span class="kwrd">char</span> buffer[256];</pre><pre><span class="lnum">   4:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   5:  </span>    sprintf( buffer, <span class="str">"update tb_char set $FIELD$ where charid = %lld;"</span>, CharID );</pre><pre><span class="lnum">   6:  </span>        </pre><pre class="alt"><span class="lnum">   7:  </span>    ExecuteCommand( buffer, Buffer, dbopr::FET_Equation );</pre><pre><span class="lnum">   8:  </span>}</pre></div>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
这段就是一个典型的DB任务, 构造函数提供了CharID和一个由结构体序列化好的buffer, $FIELD$字段, 是通过反射根据Buffer内容, 自动填充字段</p>
<p>这段例子中, $FIELD$可以填充为 hp=100, mp=100之类的. 自动填充避免了因为添加字段的到处添加代码, 还需要调试, 容易搞错</p>
<p>&nbsp;</p>
<p><strong>配置系统概念</strong></p>
<p>基于同一个配置系统, 分层实现不同的需求. 更简单的说, 解决的1个实际问题是: </p>
<p>自己改了配置文件中的ip, 上传svn后, 覆盖了别人的配置, 很多人的解决方法都是, 本地配置不提交. 但同时问题又来了:</p>
<p>当配置中有别人新加的系统配置, 怎么保证每个人都能更新到?</p>
<p>上线后, 服务器交付运维, 他们会对配置有一定程度的修改, 这个时候怎么合并程序配置和运维配置?</p>
<p>其实对于冲突的需求, 只要对系统进行分层就可以解决问题,我的处理方式:</p>
<p>配置分为:</p>
<p>全局配置: 所有服务的总体配置</p>
<p>单服务配置: 本服务的配置, 涉及网络及逻辑</p>
<p>本地配置: 这个配置每个人一份, 不上传SVN</p>
<p>命令行配置: 格式和前面的一致, 这块就可以通过运维进行配置</p>
<p>总体结构其实就是OO的派生概念, 下层可以覆盖, 修改上层的配置</p>
<p>&nbsp;</p>
<p><strong>服务器互联及识别框架</strong></p>
<p>基本功能: 基于一些简单的配置就可以将多台服务器, 同种类的不同服务器互相连接起来, 断线自动重连.</p>
<p>服务器连接后, 所有服务器可知晓并可自动按需连接</p>
<p>逻辑端也很方便的进行广播或者单独发送等</p>
<p>也就是说, 每个服务器的连接和接受端都是带识别名称或id的.</p>
<p>后面觉得这套东西实在是做的复杂, 多整出一台中心服务器来做. 但好歹框架稳定下来了, 也就好了.</p>
<p>&nbsp;</p>
<p><strong>基于lua的服务器web后台框架</strong></p>
<p>思想是很不错的,&nbsp; C++ 配合lua本身绝对是个失败</p>
<p>问题出在web处理,本身都是一个同步阻塞过程, 而这个后台框架是异步方式来做, 所以特别别扭</p>
<p>不过比起以前的本地GM系统, 这块的设计是伟大的进步</p>
<p>&nbsp;</p>
<p>现在正在设计基于golang的服务器框架, 基本框架已经完工, 等待编写逻辑后的实战测试</p>
<p>以上的很多思想在golang的服务器框架都有改进, 特别是golang本身做web也是优秀的, 外加martini这种牛X框架, 更是水到渠成</p>
<p>如果你对服务器框架设计有特别的认识, 或者想碰撞思想, 可以加博客群 309800774或者我的qq: 20998333讨论</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/209225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-12-18 16:39 <a href="http://www.cppblog.com/sunicdavy/archive/2014/12/18/209225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在liteide中， 自动get第三方包</title><link>http://www.cppblog.com/sunicdavy/archive/2014/11/27/208971.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 27 Nov 2014 09:19:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/11/27/208971.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/208971.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/11/27/208971.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/208971.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/208971.html</trackback:ping><description><![CDATA[<p>LiteIDE中有一个get按钮可以模拟go get –v 的操作</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/liteide-_F29A/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/liteide-_F29A/image_thumb.png" width="321" height="53"></a></p> <p>但默认因为找不到git而报错。 解决方法如下：</p> <p>在<a title="http://git-scm.com/downloads" href="http://git-scm.com/downloads">http://git-scm.com/downloads</a>下载对应平台git</p> <p>在LiteIDE的查看-&gt;编辑环境变量中， 修改PATH， 加入git路径。例如</p> <p>PATH=c:\mingw64\bin;%GOROOT%\bin;c:\Program Files (x86)\Git\bin;%PATH%</p> <p>再按下Get键， 第三方包就会自动更新了</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/208971.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-11-27 17:19 <a href="http://www.cppblog.com/sunicdavy/archive/2014/11/27/208971.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux x64平台golua的安装及使用</title><link>http://www.cppblog.com/sunicdavy/archive/2014/03/18/206207.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 18 Mar 2014 04:51:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/03/18/206207.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/206207.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/03/18/206207.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/206207.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/206207.html</trackback:ping><description><![CDATA[<p>这里使用的golua版本是<a title="https://github.com/aarzilli/golua" href="https://github.com/aarzilli/golua">https://github.com/aarzilli/golua</a></p> <p>按照作者的安装方法在天朝行不通的, 原因你懂的</p> <p>因此进入这个链接, 点击右边的Download ZIP下载快照包</p> <p>下载好后放到你的GOPATH指定路径, 整理路径如下</p> <p>github.com\aarzilli\golua\</p> <p>其下的目录如下</p> <p>example\<br>&nbsp;&nbsp;&nbsp; lua\<br>&nbsp;&nbsp;&nbsp; LICENSE<br>&nbsp;&nbsp;&nbsp; README.md<br>&nbsp;&nbsp;&nbsp; TODO</p> <p>然后准备lua5.1的开发包</p> <p>lua-5.1.4.tar.gz</p> <p>还有2个第三方依赖包</p> <p>readline-6.2.tar.gz</p> <p>ncurses-5.9.tar.gz</p> <p>直接configure –&gt; make install 装好</p> <p>&nbsp;</p> <p>go env确认你的GOPATH已经指向你的开发目录</p> <p>golua默认使用cgo进行编译, 可能会报错, 修改lua.go的cgo定义如下</p> <p>#cgo linux,!llua,!luaa LDFLAGS: -llua -lm –ldl</p> <p>进入$GOPATH\src\github.com\aarzilli\golua\lua</p> <p>执行go install</p> <p>完成</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/206207.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-03-18 12:51 <a href="http://www.cppblog.com/sunicdavy/archive/2014/03/18/206207.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Go 1.3+ 编译器变革</title><link>http://www.cppblog.com/sunicdavy/archive/2014/01/22/205525.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 22 Jan 2014 04:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/01/22/205525.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/205525.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/01/22/205525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/205525.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/205525.html</trackback:ping><description><![CDATA[<h3>概述</h3> <p>目前Go编译器是C写的，是时候换成Go啦。 <h5>背景</h5> <p>“gc"Go工具链来自Plan 9编译器的工具链。组装器、C编译器和链接器基本没变。Go的编译器(cmd/gc,cmd/5g,cmd/6g,cmd/8g)是配合工具链写的新的C程序。 <p>项目起始时，用C而不是Go写编译器有很多好处。突出的比如，首先，那时候Go还不存在，没法儿写编译器。而且实际上，就算存在，也会经常有明显的不兼容的变化。用C不用Go可以避免初始和持续开发导致的问题。然而如今Go 1已经稳定，所以这些持续的问题减少了很多。 <p>持续开发的问题已经消除，为了让Go实现的编译器比C更有吸引力，另一些工程问题出现： <ul> <li> <p>写正确的Go代码比写正确的C代码更容易。</p> <li> <p>调试错误的Go代码比调试错误的C代码更容易。</p> <li> <p>使用Go编译器需要对Go有一定理解。而用C编译器还需要一定理解C。</p> <li> <p>Go使并发执行比C更方便。</p> <li> <p>Go有更好的标准支持模块化，自动重写，单元测试和性能分析。</p> <li> <p>Go比C更有趣(fun)。</p></li></ul> <p>基于以上理由，我们相信是时候用Go写Go编译器啦。 <h5>计划设想</h5> <p>我们打算用自动化翻译工具来用Go重写现在C的编译器。这个翻译需要一些阶段，将从Go 1.3开始持续到未来的发行版。 <p>第一阶段。开发和调试一个自动化翻译工具。这可以在日常开发时同步进行。而且，人们还可以在这个阶段为C编译器继续改进。这个工具工作量很大，不过我们有信心完成这个特殊使命的工具。有许多C的观念没法儿直接转换成Go；macros(宏)，unions(联合，共用体,)，bit fields(位域)可能最先考虑。比较幸运（不是巧合），这些功能功能用的少，都会被翻译掉。指针运算和数组也需要一些转换工作，尽管编译器里很少。编译器里主要是tree(树)和linked list(链表)。翻译工具会保留注释和C代码的结构，所以翻译后的代码和当前的编译器代码一样可阅读。 <p>第二阶段。用翻译工具转换C代码到Go，并删除C源码。这时我们已经开始翻译，但是Go还是运行在C编译器上。非常乐观的，这可能发生在Go 1.3。不过更可能是Go 1.4。 <p>第三阶段。使用一些工具，可能来自gofix和the Go oracle，拆分编译器到包，清理和文档化代码，添加适当的单元测试。这是编译器会是地道的Go程序。目前打算在Go 1.4实现。 <p>第四a阶段。使用标准的分析和测试工具优化编译器的CPU和内存使用。可能要引入并行。如果真这样，<a href="http://blog.golang.org/race-detector">Race Detector</a>(Go的并行竞争检测工具,)会有很大帮助。这目标在Go 1.4，可能部分会延后到1.5。基本的优化分析会在第三阶段完成。 <p>第四b阶段。（和四a几段同时进行）当编译器依照明显的界限分割成包之后，需要明确引入一个中介码，在结构无关的无序树(Node_s)和结构相关的有序链表(Prog_s)之间。这个中介码应该不依赖整体架构，但是包含准确的执行顺序信息，可以用于有顺序但是结构无关的操作的优化，比如清理多余的nil检测和出界检测。这些过程基于<a href="http://en.wikipedia.org/wiki/Static_single_assignment_form">SSA</a>（静态单赋值），你可以从Alan Donovan的 go.tools/ssa 包中了解更多。 <p>第五阶段。替换go/parser和go/types到最新（全新）的版本。Robert Griesemer参考现在的经验，讨论了设计新的parser和types的可能。如果联系他们到编译器后端，相信对设计新的API有很大帮助。 <p><strong>自展（Bootstrapping）</strong>用Go语言实现的Go的编译器，从一开始就要考虑如何自展。我们考虑的规则就是Go1.3编译器必须由Go1.2编译，Go1.4的编译器必须由Go1.4编译，以此类推。 <p>这时，我们就有了一个清晰的流程来生成当前的程序：编译Go1.2的工具链（由C编写），然后使用它编译Go1.3的工具链，以此类推。这里需要一个脚本来做这个事情，来保证只会消耗CPU的时间而非某个人的时间。这样的自展，每个机器只会做一次，Go1.x的工具链将会在本地保留，并在执行all.bash来编译Go1.(x+1)工具链的时候被再次使用。 <p>显然，随着时间的推移这种自举方式是不充分的。在后面的多个版本被发布之前，为编译器写一个后端来生成C代码也许是一个更有意义的事情。这些C代码不要求效率或可读性，只要正确即可。这些C代码将会被签入，就像我们签入由yacc生成的y.tab.c文件一样。这样，自展过程就会变成：先用gcc编译C代码生成一个自展编译器，然后使用这个自展编译器来编译真正的编译器。类似于另一个自展过程，这个自展编译器将会在本地保留，并在每次执行all.bash的时候重复使用（不用重新编译）。 <p><strong>替代选择</strong>还有一些比较明显的替代方案，需要我们说明一下为什么放弃了这些选择。 <p>从一开始写一个编译器。现在的编译器有一个非常重要的特征：他们能够正常工作（或者其至少能够满足所有用户的要求）。尽管Go语言比较简单，但是编译器中有很多细微的细节优化和改写，直接丢弃10或数年的在这上面的努力是比较愚蠢的。 <p>对编译器进行人工翻译。我们已经以人工的方式翻译了一小部分C/C++代码到Go语言了。这个过程是枯燥而且易错的，且这些错误非常的细微及难以发现。相反，使用机械翻译会形成一些比较一致的错误，而这些错误是易于发现的；而且不会因为枯燥的过程开小差。Go编译器的代码明显的比我们翻译的代码多很多：超过60,000行C代码，机械翻译会使这个过程容易一些。就像Dick Sites在1974年说的一样：“相比写程序，我宁愿写一个程序来帮我写程序。“ 使用机械来翻译编译器也方便于在准备好切换之前，我们可以继续开发完善现有的C程序。 <p>只翻译后端并链接到go/parser和go/types.从前端传给后端的数据结构所包含的信息中，go/parser和go/types所能提供的除了API就没其他的东西了。如果使用这些库来替代前端，需要写代码来转换go/parser和go/types所能提供数据结构到后端，这是一个非常宽泛且易出错的工作。我们相信使用这些库是有意义的，但更明智的是，等到将编译器代码调整的更像Go程序，分成确定边界的、包含说明文档和单元测试子包之后再使用。 <p>放弃现有的编译器，使用gccgo（或者go/parser + go/types + LLVM, …）。现有的编译器是Go语言显得比较灵活的一个重要组成部分。如果尝试使用基于大量代码的GCC或LLVM来开发Go程序，感觉会有碍到Go语言的灵活性。另外，GCC是大量C代码（现在有部分C++）、LLVM是大量C++代码的程序。以上列举的、用于解释不使用现有编译框架代码的几个原因，也都适用于更多的类似的代码库。 <h5>C语言的长期使用</h5> <p>临近结束，这个计划还留下了由C写成的Plan9的工具链的一部分。在长期发展中，还是将所有的C从代码树排除掉比较好。本章节推测了一下这件事将会如何发生，但不保证其指定会发生或者按照这种套路发生。 <p>运行时包(runtime)。 runtime包的大部分都是用C写成，基于一些同样的原因，Go编译器也是用C实现。但是，runtime包远比编译器的代码量要小，且它现在已经是用Go和C混合编写。将C代码转换为Go代码时，一次转化一部分貌似也是可行的。其中，主要部分有：调度器（scheduler），垃圾回收（the garbage collector），散列映射表（hash map）的实现，和channel的实现。（这里Go和C代码混合的很融洽，是因为这里使用的6c而不是gcc来编译的C代码。） <p>C编译器。 Plan 9的C编译器本身就是用C写成，如果我们要从Go包实现里面移除所有的C代码，那么我们将移除这些编译工具：“go tool 6c”等等，另外，.c的文件也将不被支持出现的Go包的目录里面。我们应该提前声明这样的计划，以便使用C的第三方包有时间去移除这类C代码的使用。（Cgo，由于使用了gcc来替代6c，所以它仍然可以作为一个途径来在Go包中使用C实现部分功能。）在Go1的兼容性文档中没有包含工具链修改的描述，也就是说去掉C编译器是被允许的。 <p>汇编器。 Plan 9的汇编器也是用C实现的，但这个汇编器只不过是一系列解析树组成的简单解析器，这使得不论手动还是自动将它翻译成Go语言都比较简单。 <p>连接器。 Plan 9的连接器也是由C写成。最近的一些工作，已经将大部分的连接器工作放到的编译器中，而且，也已经有个计划将剩余的部分重写成一个新的、更简单的Go程序。转移到编译器的部分连接器代码，现在需要随着编译器的原有代码一起进行翻译。 <p>基于Libmach的工具: nm, pack, addr2line, 和objdump。 Nm现在已经使用Go语言重写。Pack和addr2line可以任何一天被重写。Objdump现在依赖于libmach的反汇编器，但这些转换为Go也是比较简单的，不论是使用机械还是人工翻译。所以基于这几点，libmach本身将来也可以被移除。 <p>&nbsp; <p>来源: <a href="http://www.oschina.net/translate/go-1-3-compiler-overhaul">http://www.oschina.net/translate/go-1-3-compiler-overhaul</a> <p>英文来源:<a title="https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdwTuF7WWLux71CYD0eeD8/preview?sle=true&amp;pli=1" href="https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdwTuF7WWLux71CYD0eeD8/preview?sle=true&amp;pli=1">https://docs.google.com/document/d/1P3BLR31VA8cvLJLfMibSuTdwTuF7WWLux71CYD0eeD8/preview?sle=true&amp;pli=1</a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/205525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-01-22 12:23 <a href="http://www.cppblog.com/sunicdavy/archive/2014/01/22/205525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>go语言开发环境LiteIDE自动完成功能失效解决方法</title><link>http://www.cppblog.com/sunicdavy/archive/2014/01/03/205147.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 03 Jan 2014 11:10:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2014/01/03/205147.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/205147.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2014/01/03/205147.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/205147.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/205147.html</trackback:ping><description><![CDATA[<p>比较过LiteIDE和eclipse+goclipse, 最后还是觉得LiteIDE简洁.但发现其自动完成功能偶尔会出现, 随即搜索, 发现其使用gocode的一个开源项目开了一个简单服务, 为各种IDE提供高速的自动完成服务.在goclipse环境发现其报了版本不匹配的错, 而最近go的更新也是很频繁, 所以觉得应该是gocode版本过老造成.</p> <p>搜索到gocode的开发页面<a href="https://github.com/nsf/gocode">https://github.com/nsf/gocode</a>&nbsp; 结果发现nsf这家伙居然也是luaBridge的作者. </p> <p>下载最新的gocode代码, 解压后, 编译:</p> <p>windows下命令行</p> <p>go build gocode.go autocompletecontext.go autocompletefile.go client.go config.go cursorcontext.go decl.go declcache.go formatters.go os_windows.go package.go ripper.go rpc.go scope.go server.go utils.go</p> <p>linux下, 只需要将os_windows.go换为os_posix.go即可</p> <p>编译完成后, 将可执行文件gocode覆盖到liteIDE下的同名文件, 杀掉gocode进程后重启liteIDE即可</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/fbf779bcb634_10ACB/image_2.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/fbf779bcb634_10ACB/image_thumb.png" width="244" height="217"></a></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/205147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2014-01-03 19:10 <a href="http://www.cppblog.com/sunicdavy/archive/2014/01/03/205147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>luabind 0.9.1在boost 1.49+和gcc-4.6.3以上版本的编译问题处理</title><link>http://www.cppblog.com/sunicdavy/archive/2013/09/24/203409.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 24 Sep 2013 08:46:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2013/09/24/203409.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/203409.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2013/09/24/203409.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/203409.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/203409.html</trackback:ping><description><![CDATA[<p>将boost更新到1.53时, 发现luabind死活编译不过, 报错如下</p> <p>error: missing binary operator before token "("</p> <p>根据老外的描述, boost中的BOOST_PP_ITERATION_FLAGS从1.49版本后发生了一些变化.</p> <p>在git找到一个patch, 链接<a href="https://gist.github.com/ObKo/2011636">在此</a></p> <p>以下简单描述</p> <p>修改call_function.hpp, call_member.hpp及wrapper_base.hpp</p> <p>去掉#elif BOOST_PP_ITERATION_FLAGS() == 1</p> <p>更换为</p> <p>#else</p> <p>#if BOOST_PP_ITERATION_FLAGS() == 1</p><pre><p>然后在源码底部加一个#endif即可</p></pre><img src ="http://www.cppblog.com/sunicdavy/aggbug/203409.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2013-09-24 16:46 <a href="http://www.cppblog.com/sunicdavy/archive/2013/09/24/203409.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>捕获Linux段错误(Segment fault)并且打印错误堆栈</title><link>http://www.cppblog.com/sunicdavy/archive/2012/12/29/196809.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Sat, 29 Dec 2012 09:53:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/12/29/196809.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/196809.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/12/29/196809.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/196809.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/196809.html</trackback:ping><description><![CDATA[<p>Linux上跑服务器如果遇到程序崩溃是一件很苦恼的事情, 再碰到重现很难的BUG, 估计只能通过传统的排查方法进行.</p> <p>在编写本文前, 笔者使用过诸如libunwind等库进行错误时堆栈打印, 但是其本身由于需要引用第三方库, 使用还是稍微麻烦.</p> <p>经过Google后, 居然找到一篇<a href="http://blog.csdn.net/kakaka2011/article/details/6597857">好文</a>, 其通过捕获SIGSEGV信号, 并迫使程序进入gdb调试阶段, 利用gdb强大的调试功能可以进行各种错误跟踪, 此法已与Windows下程序崩溃后弹出VC调试几乎接近. </p> <p>我在此文基础上, 扩展了其通用性及便利性</p> <p>1. 使用gdb的 -ex参数, 在挂接程序后, 执行bt指令打出程序堆栈</p> <p>2. 将信息重定向到自定义的文件,在多进程都需要进行后台输出时带来更大的灵活性, 同时也解决了gdb只能在前台调试的问题</p> <p>代码如下</p><pre class="csharpcode">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;signal.h&gt;
#include &lt;<span class="kwrd">string</span>.h&gt;

<span class="kwrd">void</span> dump(<span class="kwrd">int</span> signo)
{
        <span class="kwrd">char</span> buf[1024];
        <span class="kwrd">char</span> cmd[1024];
        FILE *fh;

        snprintf(buf, <span class="kwrd">sizeof</span>(buf), <span class="str">"/proc/%d/cmdline"</span>, getpid());
        <span class="kwrd">if</span>(!(fh = fopen(buf, <span class="str">"r"</span>)))
                exit(0);
        <span class="kwrd">if</span>(!fgets(buf, <span class="kwrd">sizeof</span>(buf), fh))
                exit(0);
        fclose(fh);
        <span class="kwrd">if</span>(buf[strlen(buf) - 1] == <span class="str">'/n'</span>)
                buf[strlen(buf) - 1] = <span class="str">'/0'</span>;
        snprintf(cmd, <span class="kwrd">sizeof</span>(cmd), <span class="str">"gdb %s %d -ex=bt &gt; ./a.txt"</span>, buf, getpid());
        system(cmd);

        exit(0);
}</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>在服务器开启时,添加 signal(SIGSEGV, &amp;dump ); 进行信号处理挂接即可</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>引用: <a title="http://blog.csdn.net/kakaka2011/article/details/6597857" href="http://blog.csdn.net/kakaka2011/article/details/6597857">http://blog.csdn.net/kakaka2011/article/details/6597857</a>&nbsp; 作者: kakaka2011</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/196809.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-12-29 17:53 <a href="http://www.cppblog.com/sunicdavy/archive/2012/12/29/196809.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>恼人的boost::asio::async_read_until</title><link>http://www.cppblog.com/sunicdavy/archive/2012/12/03/195921.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 03 Dec 2012 07:12:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/12/03/195921.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/195921.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/12/03/195921.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/195921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/195921.html</trackback:ping><description><![CDATA[<p>最近为服务器添加XMLSocket与Flash进行通信, 这种协议其实是一种以\0结尾的字符串协议, 为了让asio兼容此协议, 我从文档找到了async_read_until异步读取系列, 这个函数的原理时, 给定一个streambuf, 和一个分隔符, asio碰到分隔符时返回, 你可以从streambuf中读取需要的数据. 看似很简单, 我很快写好一个demo与Flash进行通信, 结果发现在一个echo逻辑速度很快时, 服务器居然乱包了, 网上查了下, 官方原文是这样的:</p> <p>”After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter. An application will typically leave that data in the streambuf for a subsequent async_read_until operation to examine.”</p> <p>意思是, streambuf中并不一定是到分隔符前的所有数据, 多余的数据可能一样会在streambuf中. 也就是说, 还需要自己再次处理一遍数据...</p> <p>动手呗, async_read_until看似就是一个废柴, 底层已经费了很多CPU在逐字符与分隔符的匹配上, 抛上来的数据居然还是半成品.</p> <p>代码如下, 测试通过, 但是实在很费解为啥非要再做一次..</p><pre class="csharpcode">          boost::asio::streambuf* SB = SBP.get();

            <span class="rem">// 访问缓冲</span>
            <span class="kwrd">const</span> <span class="kwrd">char</span>* Buffs = boost::asio::buffer_cast&lt;<span class="kwrd">const</span> <span class="kwrd">char</span>*&gt;( SB-&gt;data() );

            uint32 DataSize = 0;
            <span class="kwrd">for</span> ( uint32 i = 0; i &lt; SB-&gt;size(); ++i )
            {
                <span class="kwrd">const</span> <span class="kwrd">char</span> DChar = Buffs[i];

                <span class="rem">// 这里需要自己判断字符串内容, read_until的文档里这么说的</span>
                <span class="kwrd">if</span> ( DChar == <span class="str">'\0'</span> )
                {
                    DataSize = i;
                    <span class="kwrd">break</span>;
                }
            }

            <span class="kwrd">if</span> ( DataSize &gt; 0 )
            {
                <span class="rem">// 取成字符串</span>
                std::<span class="kwrd">string</span> FullText( Buffs, DataSize );
                
                <span class="rem">// 消费</span>
                SB-&gt;consume( DataSize );                

                mWorkService-&gt;post(
                    boost::bind(&amp;AsioSession::NotifyReadString,
                    shared_from_this(),
                    FullText )
                    );

            }</pre><pre class="csharpcode"><font size="2" face="Verdana">  另外, 为了保证输入性安全, 可以在streambuf构造时加一个最大一个读取量, 超过此量会返回报错, 避免了缓冲区被撑爆的危险</font></pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style><img src ="http://www.cppblog.com/sunicdavy/aggbug/195921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-12-03 15:12 <a href="http://www.cppblog.com/sunicdavy/archive/2012/12/03/195921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL++操作MySQL中造成Commands out of sync的2014错误分析</title><link>http://www.cppblog.com/sunicdavy/archive/2012/06/13/178678.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 13 Jun 2012 09:57:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/06/13/178678.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/178678.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/06/13/178678.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/178678.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/178678.html</trackback:ping><description><![CDATA[<p>MySQL++在MySQL原始C接口上做了一些封装, 给操作带来很大便利.</p> <p>最近遇到DB服务器中报出一个MySQL的错误:Commands out of sync; you can't run this command now,2014</p> <p>查阅很多代码, 解决方法都是使用C接口的方式, 模仿其解决方法,在MySQL++中找到了比较好的解决方案:</p> <p><strong>方案A</strong>: 清空每次未使用的记录</p><pre class="csharpcode"><span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; DataQuery.more_results(); ++i)
{
   DataQuery.store_next();                
}</pre>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>其中 DataQuery类型为mysqlpp::Query</p>
<p>&nbsp;</p>
<p><strong>方案B</strong>: 对于存储过程中,使用了多个select语句返回同样的列结果, 就需要使用以下语句</p>
<div class="csharpcode"><pre class="alt"><span class="kwrd">static</span> <span class="kwrd">void</span> print_multiple_results(Query&amp; query)</pre><pre>{</pre><pre class="alt">    <span class="rem">// 执行查询并输出结果表</span></pre><pre> StoreQueryResult res = query.store();</pre><pre class="alt"> print_result(res, 0);</pre><pre> <span class="kwrd">for</span> (<span class="kwrd">int</span> i = 1; query.more_results(); ++i) {</pre><pre class="alt">  res = query.store_next();</pre><pre>  print_result(res, i);</pre><pre class="alt"> }</pre><pre>}</pre><pre>&nbsp;</pre><pre>参考文章:<a href="http://hi.baidu.com/freeknight/item/ea9fd88e7d291f854514cf43">http://hi.baidu.com/freeknight/item/ea9fd88e7d291f854514cf43</a></pre></div><img src ="http://www.cppblog.com/sunicdavy/aggbug/178678.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-06-13 17:57 <a href="http://www.cppblog.com/sunicdavy/archive/2012/06/13/178678.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于HG版本管理软件的服务器/客户端数据版本发布流程</title><link>http://www.cppblog.com/sunicdavy/archive/2012/04/26/172798.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 26 Apr 2012 03:11:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/04/26/172798.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/172798.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/04/26/172798.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/172798.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/172798.html</trackback:ping><description><![CDATA[<h1><font face="Lucida Console">传统发布现状</font></h1>
<p><font face="Lucida Console">传统的服务器/客户端版本发布流程都需要经历以下流程:</font></p>
<p><font face="Lucida Console">1. 获取代码</font></p>
<p><font face="Lucida Console">2. 编译代码</font></p>
<p><font face="Lucida Console">3. 将配置,二进制文件, 资源打包</font></p>
<p><font face="Lucida Console">4. 挂接远程服务器磁盘拷贝打包文件</font></p>
<p><font face="Lucida Console">5. 远程操作解压打包文件</font></p>
<p><font face="Lucida Console">6. 修改设置,指向最新版本</font></p>
<p><font face="Lucida Console">7. 重启服务器</font></p>
<p><font face="Lucida Console">此流程繁琐,重复且无聊, 同时, 由于网络带宽,网速等约束, 每次若使用完整包发布,传输起来非常吃力</font></p>
<p><font face="Lucida Console">本文讨论的外网服务器由于安全性要求,禁止root登录,只能用普通帐号登录或传输后, 提权为root继续进行以上操作, 因此rsync的使用受到严重限制</font></p>
<p><font face="Lucida Console">即便使用Windows下的同步软件, 也几乎不可能.</font></p>
<h1><font face="Lucida Console">HG特性及优势</font></h1>
<p><font face="Lucida Console">HG作为一个优秀,小巧的跨平台代码管理软件的特性,正好能解决以上问题, 主要特性:</font></p>
<p><font face="Lucida Console">1. 安装简便, 可以使用代码直接安装</font></p>
<p><font face="Lucida Console">2. 利用本地映射版本可以对新版本做差异比较</font></p>
<p><font face="Lucida Console">3. 增量包传输, 100%同步, 本地文件删除后, 远程文件也会同步删除</font></p>
<p><font face="Lucida Console">4. 传输压缩</font></p>
<p><font face="Lucida Console">5. 增量包可以打包为patch进行离线更新</font></p>
<p><font face="Lucida Console">6. 可以恢复到任意版本, 提交版本有据可查</font></p>
<p><font face="Lucida Console"></font>&nbsp;</p>
<p><strong><font face="Lucida Console">以下部署系统以CentOS为基础, 其他系统类似</font></strong></p>
<p><strong><font face="Lucida Console">本文来自战魂小筑的博客<a href="http://www.cppblog.com/sunicdavy">http://www.cppblog.com/sunicdavy</a> 转载请注明来源</font></strong></p>
<h1><font face="Lucida Console">为远程服务器安装HG </font></h1>
<h2><font face="Lucida Console">安装依赖库</font></h2>
<p><font face="Lucida Console">yum install python-devel</font> </p>
<h2><font face="Lucida Console">获取HG源码</font></h2>
<p><font face="Lucida Console">wget </font><a href="http://mercurial.selenic.com/release/mercurial-2.1.tar.gz"><font face="Lucida Console">http://mercurial.selenic.com/release/mercurial-2.1.tar.gz</font></a> </p>
<p><font face="Lucida Console">tar zxvf ./mercurial-2.1.tar.gz</font> </p>
<h2><font face="Lucida Console">编译安装</font></h2>
<p><font face="Lucida Console">make all</font> </p>
<p><font face="Lucida Console">make install</font> </p>
<p><font face="Lucida Console">hg debuginstall</font> </p>
<p><font face="Lucida Console"></font>&nbsp; </p>
<h1><font face="Lucida Console">使用HG同步数据</font></h1>
<h2><font face="Lucida Console">创建仓库</font></h2>
<p><font face="Lucida Console">找到你需要同步的目录,进入目录</font></p>
<p><font face="Lucida Console">执行</font></p>
<p><font face="Lucida Console">hg init</font></p>
<p><font face="Lucida Console">vi .hg/hgrc</font></p>
<p><font face="Lucida Console">添加以下内容,让这个仓库支持外部push</font></p>
<p><font face="Lucida Console">[ui]</font></p>
<p><font face="Lucida Console">username=<font color="#ff0000">服务器提交后看到的用户名</font></font></p>
<p><font face="Lucida Console">[web]<br /></font></p>
<p><div>push_ssl = false</div><font face="Lucida Console">allow_push=*<br /></font></p>
<h2><font face="Lucida Console">同步</font></h2>
<p><font face="Lucida Console">vi /etc/sysconfig/iptables</font></p>
<p><font face="Lucida Console">添加HG服务的8000端口</font></p>
<p><font face="Lucida Console">-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8000 -j ACCEPT</font></p>
<p><font face="Lucida Console">开启仓库同步服务</font></p>
<p><font face="Lucida Console">hg serve</font></p>
<p><font face="Lucida Console">本地机器同样找到文件夹,创建仓库</font></p>
<p><font face="Lucida Console">hg init</font></p>
<p><font face="Lucida Console">以后每次需要同步时,使用命令,或者乌龟HG的界面工具拉取服务器数据即可</font></p>
<p><font face="Lucida Console">hg pull http://服务器地址:8000</font></p>
<p><font face="Lucida Console"></font>&nbsp;</p>
<p><font face="Lucida Console">版本提交方法与HG日常使用类似, 这里不再阐述</font></p>
<h1><font face="Lucida Console">离线更新</font></h1>
<p>对于某些服务器深处防火墙或者安全登录后方,不能直接开启8000端口的情况</p>
<p>可以使用hg导出一个patch, 传输到远程服务器, 使用hg import PATCH 即可</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/172798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-04-26 11:11 <a href="http://www.cppblog.com/sunicdavy/archive/2012/04/26/172798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>让C/C++程序一次编译可以发布到多版本Linux之上</title><link>http://www.cppblog.com/sunicdavy/archive/2012/04/20/172108.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Fri, 20 Apr 2012 03:35:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/04/20/172108.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/172108.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/04/20/172108.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/172108.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/172108.html</trackback:ping><description><![CDATA[<p>最近页游开放平台比较多, 每个平台要求的Linux版本各不相同, 这给开发人员部署服务器带来了很大的困难. 在本机Linux编译的程序,发布时即便将依赖的so附带到目标Linux环境,仍然会碰到依赖及版本问题,例如:</p> <p><font face="Lucida Console">[root@localhost bin]# ldd wkcenter <br /><font color="#ff0000">./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./wkcenter)<br />./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./wkcenter)<br />./wkcenter: /usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./wkcenter)<br />./wkcenter: /lib/libc.so.6: version `GLIBC_2.9' not found (required by ./wkcenter)<br />./wkcenter: /lib/libc.so.6: version `GLIBC_2.7' not found (required by ./wkcenter)<br />./wkcenter: /lib/libc.so.6: version `GLIBC_2.8' not found (required by ./wkcenter)<br />./wkcenter: /lib/libc.so.6: version `GLIBC_2.11' not found (required by ./wkcenter)</font><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; linux-gate.so.1 =&gt;&nbsp; (0xffffe000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; liblog4cpp.so.4 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libprotobuf.so.7 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libboost_filesystem.so.1.48.0 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libboost_system.so.1.48.0 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libboost_thread.so.1.48.0 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libboost_program_options.so.1.48.0 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libunwind-x86.so.7 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libluabind.so.0.9.0 =&gt; not found<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libstdc++.so.6 =&gt; /usr/lib/libstdc++.so.6 (0x008ae000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libm.so.6 =&gt; /lib/libm.so.6 (0x0044b000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libgcc_s.so.1 =&gt; /lib/libgcc_s.so.1 (0x00476000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libc.so.6 =&gt; /lib/libc.so.6 (0x002c1000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; libpthread.so.0 =&gt; /lib/libpthread.so.0 (0x0041d000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; librt.so.1 =&gt; /lib/librt.so.1 (0x00440000)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /lib/ld-linux.so.2 (0x002a2000)</font><br /></p> <p>上面红字部分表示glibc及glibcxx库依赖不正确. 本人使用的Linux编译版本为Mint 11(基于Ubuntu), 一般Ubuntu发行版的glibc配备非常高. 但是上文中的发布的Linux版本为CentOS 5.8</p> <p>使用/lib/libc.so.6 查看libc版本为2.5, 远远低于开发环境的2.11</p> <p><font face="Lucida Console">GNU C Library stable release version <font color="#ff0000">2.5</font>, by Roland McGrath et al.<br />Copyright (C) 2006 Free Software Foundation, Inc.<br />This is free software; see the source for copying conditions.<br />There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A<br />PARTICULAR PURPOSE.<br />Compiled by GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-51).<br />Compiled on a Linux 2.6.9 system on 2012-02-21.<br />Available extensions:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The C stubs add-on version 2.1.2.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; crypt add-on version 2.1 by Michael Glad and others<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GNU Libidn by Simon Josefsson<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GNU libio by Per Bothner<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Native POSIX Threads Library by Ulrich Drepper et al<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BIND-8.2.3-T5B<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RT using linux kernel aio<br />Thread-local storage support included.<br />For bug reporting instructions, please see:<br />&lt;</font><a href="http://www.gnu.org/software/libc/bugs.html"><font face="Lucida Console">http://www.gnu.org/software/libc/bugs.html</font></a><font face="Lucida Console">&gt;.</font></p> <p><font face="Lucida Console">由于Linux操作系统的特有elf加载顺序. (可以参考<a href="http://www.iteedu.com/os/linux/mklinuxdiary/ch4mksystem/4.php">此文</a>). 虽然可以很大程度上解决Windows早期版本的dll hell问题, 但是给部署带来了很大难度</font></p> <p><font face="Lucida Console">一般常见的解决方法是, 找到一个与目标Linux版本及glibc版本一致的Linux, 将代码及依赖包放在之上编译, 完成后再发布.这种方法与Linux下常见软件安装方法类似. 但是对于商用服务器部署步骤来说未免繁琐, 安全性低.</font></p> <p>还有一种方法,使用静态链接. 将所有可执行文件文件依赖的静态库, 系统库,全部静态链接到可执行文件中,可以一次性解决这个问题</p> <p>步骤:</p> <p>&nbsp;&nbsp;&nbsp; 1. 在gcc链接命令行中添加-static -static-libgcc -static-libstdc++</p> <p>&nbsp;&nbsp;&nbsp; 2. 将第三方依赖库打开静态链接开关, 将原来链接.so的库,全改为链接.a</p> <p>&nbsp;&nbsp;&nbsp; 3. gcc对链接库顺序很敏感, 链接库顺序需要按照从前至后为:&nbsp; 项目产生的静态库 &gt; 第三方库静态库 &gt; 系统静态库</p> <p>&nbsp;&nbsp;&nbsp; 4. 链接时, 若有未解决的symbol, 可以尝试在最后添加-lpthread及-lrt解决</p> <p>&nbsp;&nbsp;&nbsp; </p> <p>在发布版本Linux上运行可能遇到的问题:</p> <p><font face="Lucida Console">terminate called after throwing an instance of 'std::runtime_error'</font> </p><p><font face="Lucida Console">what(): locale::facet::_S_create_c_locale name not valid</font> </p><p>解决方法: 执行之前运行export LC_ALL="C"  </p><img src ="http://www.cppblog.com/sunicdavy/aggbug/172108.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-04-20 11:35 <a href="http://www.cppblog.com/sunicdavy/archive/2012/04/20/172108.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux服务自动安装卸载部署脚本</title><link>http://www.cppblog.com/sunicdavy/archive/2012/04/12/171026.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 12 Apr 2012 01:33:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/04/12/171026.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/171026.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/04/12/171026.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/171026.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/171026.html</trackback:ping><description><![CDATA[<pre class="csharpcode"><span class="rem">#!/bin/bash</span>
<span class="rem"># chkconfig: 3 3 1</span>
<span class="rem"># description: svclauncher</span></pre><pre class="csharpcode">ServicePath=/usr/<span class="kwrd">local</span>/bin

ServiceList=(
<span class="str">"wkcenterd --toc /home/davy/dev/kaze/Config/CenterService.toc --logfile /tmp/centerd.log"</span>
<span class="str">"wkagentd --toc /home/davy/dev/kaze/Config/AgentService.toc --logfile /tmp/agentd.log"</span>
)

StartAll()
{
    <span class="kwrd">for</span>((i = 0;i&lt;${<span class="rem">#ServiceList[*]};i=i+1))</span>
    do

     echo <span class="str">"start:"</span> $ServicePath/${ServiceList[i]}
     $ServicePath/${ServiceList[i]} &gt; /dev/null &amp;

    done
}

StopAll()
{
    <span class="kwrd">for</span>((i = 0;i&lt;${<span class="rem">#ServiceList[*]};i=i+1))</span>
    do

     echo <span class="str">"stop:"</span> $ServicePath/${ServiceList[i]}
     svcname=`echo ${ServiceList[i]} | awk <span class="str">'{print $1}'</span>`
     killall $svcname &gt; /dev/null

    done
}

RestartAll()
{
    StopAll
    StartAll
}


InstallService()
{
    svcname=`basename $0`
    chmod +x $svcname
    cp $svcname /etc/init.d
    ln /etc/init.d/$svcname /etc/rc3.d/S03$svcname
    ln /etc/init.d/$svcname /etc/rc0.d/K03$svcname
    chkconfig --add $svcname
    chkconfig $svcname on
    chkconfig --list | grep $svcname
}

UninstallService()
{
    svcname=`basename $0`
    chkconfig --del $svcname
    rm -f /etc/init.d/$svcname
    rm -f /etc/rc3.d/S03$svcname
    rm -f /etc/rc3.d/K03$svcname
}



case <span class="str">"$1"</span> <span class="kwrd">in</span>
    start)
    StartAll
    ;;
    stop)
    StopAll
    ;;
    restart)
    RestartAll
    ;;
    install)
    InstallService
    ;;
    uninstall)
    UninstallService
    ;;
    *)
           echo <span class="str">"Usage: service $EXEC {install|start|stop|restart|uninst}"</span>
       exit 1
esac
 
exit $? </pre>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/171026.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-04-12 09:33 <a href="http://www.cppblog.com/sunicdavy/archive/2012/04/12/171026.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux下将ldd打印的依赖列表拷贝到指定目录</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/29/166791.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Wed, 29 Feb 2012 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/29/166791.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/166791.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/29/166791.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/166791.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/166791.html</trackback:ping><description><![CDATA[<p>Linux下的ldd命令可以查看一个可执行文件/共享库/静态库的依赖, 但是想得到这些依赖文件, 必须手动去找,非常麻烦</p> <p>这里是一个Shell可以将依赖列表中的文件拷贝到指定目录</p><pre class="csharpcode">deplist=$( ldd $1 | awk <span class="str">'{if (match($3,"/")){ print $3}}'</span> )
cp $deplist $2</pre><pre class="csharpcode">代码解释: ldd导出列表, 这个列表打印出来很丑</pre>
<p>linux-gate.so.1 =&gt;&nbsp; (0x00ed2000)<br>&nbsp;&nbsp;&nbsp; liblog4cpp.so.4 =&gt; /usr/local/lib/liblog4cpp.so.4 (0x00657000)<br>&nbsp;&nbsp;&nbsp; libprotobuf.so.7 =&gt; /usr/local/lib/libprotobuf.so.7 (0x00360000)<br>&nbsp;&nbsp;&nbsp; libboost_filesystem.so.1.48.0 =&gt; /usr/local/lib/libboost_filesystem.so.1.48.0 (0x00a9a000)<br>&nbsp;&nbsp;&nbsp; libboost_program_options.so.1.48.0 =&gt; /usr/local/lib/libboost_program_options.so.1.48.0 (0x00110000)<br>&nbsp;&nbsp;&nbsp; libboost_system.so.1.48.0 =&gt; /usr/local/lib/libboost_system.so.1.48.0 (0x00a85000)<br>&nbsp;&nbsp;&nbsp; libboost_thread.so.1.48.0 =&gt; /usr/local/lib/libboost_thread.so.1.48.0 (0x00179000)<br>&nbsp;&nbsp;&nbsp; libunwind-x86.so.7 =&gt; /usr/lib/libunwind-x86.so.7 (0x00821000)<br>&nbsp;&nbsp;&nbsp; libluabindd.so.0.9.0 =&gt; /usr/local/lib/libluabindd.so.0.9.0 (0x00bb3000)<br>&nbsp;&nbsp;&nbsp; libmysqlpp.so.3 =&gt; /usr/local/lib/libmysqlpp.so.3 (0x00de5000)<br>&nbsp;&nbsp;&nbsp; libstdc++.so.6 =&gt; /usr/lib/i386-linux-gnu/libstdc++.so.6 (0x001a9000)<br>&nbsp;&nbsp;&nbsp; libm.so.6 =&gt; /lib/i386-linux-gnu/libm.so.6 (0x00782000)<br>&nbsp;&nbsp;&nbsp; libgcc_s.so.1 =&gt; /lib/i386-linux-gnu/libgcc_s.so.1 (0x00aea000)<br>&nbsp;&nbsp;&nbsp; libc.so.6 =&gt; /lib/i386-linux-gnu/libc.so.6 (0x00447000)<br>&nbsp;&nbsp;&nbsp; libpthread.so.0 =&gt; /lib/i386-linux-gnu/libpthread.so.0 (0x00abd000)<br>&nbsp;&nbsp;&nbsp; librt.so.1 =&gt; /lib/i386-linux-gnu/librt.so.1 (0x00193000)<br>&nbsp;&nbsp;&nbsp; libnsl.so.1 =&gt; /lib/i386-linux-gnu/libnsl.so.1 (0x00294000)<br>&nbsp;&nbsp;&nbsp; libunwind.so.7 =&gt; /usr/lib/libunwind.so.7 (0x002ab000)<br>&nbsp;&nbsp;&nbsp; libdl.so.2 =&gt; /lib/i386-linux-gnu/libdl.so.2 (0x00e8a000)<br>&nbsp;&nbsp;&nbsp; libmysqlclient_r.so.16 =&gt; /usr/lib/libmysqlclient_r.so.16 (0x0083b000)<br>&nbsp;&nbsp;&nbsp; /lib/ld-linux.so.2 (0x00608000)<br>&nbsp;&nbsp;&nbsp; libz.so.1 =&gt; /lib/i386-linux-gnu/libz.so.1 (0x002c0000)<br></p>
<p>&nbsp;</p>
<p><font size="3" face="Consolas">我们发现第一行的so没有对应的库地址, 因此我们使用awk的脚本功能,判断第三个参数,也就是=&gt;之后的路径必须包含/</font></p>
<p><font size="3" face="Consolas">之后将第一行的输出重定向到变量中, 再使用cp指令从列表拷贝到指定目录</font>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style></p><img src ="http://www.cppblog.com/sunicdavy/aggbug/166791.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-29 16:05 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/29/166791.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux服务器守护进程+自动启动+服务配置笔记</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/28/166680.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 28 Feb 2012 02:52:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/28/166680.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/166680.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/28/166680.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/166680.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/166680.html</trackback:ping><description><![CDATA[<h4>1.1 为进程添加守护进程</h4> <p>参考链接<a href="http://yubosun.akcms.com/tech/linux-daemon-program.htm">http://yubosun.akcms.com/tech/linux-daemon-program.htm</a> <div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>#include &lt;unistd.h&gt; </pre><pre><span class="lnum">   2:  </span>#include &lt;signal.h&gt; </pre><pre class="alt"><span class="lnum">   3:  </span>#include &lt;sys/types.h&gt; </pre><pre><span class="lnum">   4:  </span>#include &lt;sys/stat.h&gt; </pre><pre class="alt"><span class="lnum">   5:  </span>#include &lt;stdio.h&gt; </pre><pre><span class="lnum">   6:  </span>#include &lt;stdlib.h&gt;</pre><pre class="alt"><span class="lnum">   7:  </span>&nbsp;</pre><pre><span class="lnum">   8:  </span>#ifndef NOFILE </pre><pre class="alt"><span class="lnum">   9:  </span><span class="preproc">#define</span> NOFILE 3 </pre><pre><span class="lnum">  10:  </span><span class="preproc">#endif</span></pre><pre class="alt"><span class="lnum">  11:  </span>&nbsp;</pre><pre><span class="lnum">  12:  </span><span class="kwrd">void</span> init_daemon() </pre><pre class="alt"><span class="lnum">  13:  </span>{ </pre><pre><span class="lnum">  14:  </span>        <span class="kwrd">int</span> pid; </pre><pre class="alt"><span class="lnum">  15:  </span>        <span class="kwrd">int</span> i; </pre><pre><span class="lnum">  16:  </span>        <span class="kwrd">if</span>(pid = fork()) exit(0); <span class="rem">//父进程，退出 </span></pre><pre class="alt"><span class="lnum">  17:  </span>&nbsp;</pre><pre><span class="lnum">  18:  </span>        <span class="kwrd">else</span> <span class="kwrd">if</span>(pid &lt; 0) exit(1); <span class="rem">//fork失败 </span></pre><pre class="alt"><span class="lnum">  19:  </span>&nbsp;</pre><pre><span class="lnum">  20:  </span>        <span class="rem">/* 子进程继续执行 */</span> </pre><pre class="alt"><span class="lnum">  21:  </span>        setsid(); <span class="rem">//创建新的会话组，子进程成为组长，并与控制终端分离 </span></pre><pre><span class="lnum">  22:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  23:  </span>        <span class="rem">/* 防止子进程（组长）获取控制终端 */</span> </pre><pre><span class="lnum">  24:  </span>        <span class="kwrd">if</span>(pid = fork()) exit(0); <span class="rem">//父进程，退出 </span></pre><pre class="alt"><span class="lnum">  25:  </span>&nbsp;</pre><pre><span class="lnum">  26:  </span>        <span class="kwrd">else</span> <span class="kwrd">if</span>(pid &lt; 0) exit(1); <span class="rem">//fork错误，退出 </span></pre><pre class="alt"><span class="lnum">  27:  </span>&nbsp;</pre><pre><span class="lnum">  28:  </span>        <span class="rem">/* 第二子进程继续执行 , 第二子进程不再是会会话组组长*/</span> </pre><pre class="alt"><span class="lnum">  29:  </span>&nbsp;</pre><pre><span class="lnum">  30:  </span>        <span class="rem">//for(i = 0; i &lt; NOFILE; i++) /* 关闭打开的文件描述符*/ </span></pre><pre class="alt"><span class="lnum">  31:  </span>        <span class="rem">//{ </span></pre><pre><span class="lnum">  32:  </span>        <span class="rem">//close(i); </span></pre><pre class="alt"><span class="lnum">  33:  </span>        <span class="rem">//} </span></pre><pre><span class="lnum">  34:  </span>        chdir(<span class="str">"/tmp"</span>); <span class="rem">/* 切换工作目录 */</span> </pre><pre class="alt"><span class="lnum">  35:  </span>        umask(0); <span class="rem">/* 重设文件创建掩码 */</span> </pre><pre><span class="lnum">  36:  </span>        <span class="kwrd">return</span>; </pre><pre class="alt"><span class="lnum">  37:  </span>}</pre><pre><span class="lnum">  38:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  39:  </span><span class="kwrd">int</span> main(<span class="kwrd">int</span> argc, <span class="kwrd">char</span>* argv[])</pre><pre><span class="lnum">  40:  </span>{    </pre><pre class="alt"><span class="lnum">  41:  </span>    FILE *fp; </pre><pre><span class="lnum">  42:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  43:  </span>    signal(SIGCHLD, SIG_IGN); <span class="rem">/* 忽略子进程结束信号，防止出现僵尸进程 */</span> </pre><pre><span class="lnum">  44:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  45:  </span>    init_daemon(); </pre><pre><span class="lnum">  46:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  47:  </span>    <span class="kwrd">while</span>(1) </pre><pre><span class="lnum">  48:  </span>    { </pre><pre class="alt"><span class="lnum">  49:  </span>            sleep(1);</pre><pre><span class="lnum">  50:  </span>            </pre><pre class="alt"><span class="lnum">  51:  </span><span class="rem">// 注意, 日志写到这个目录</span></pre><pre><span class="lnum">  52:  </span>            <span class="kwrd">if</span>((fp = fopen(<span class="str">"/var/tmp/test.log"</span>, <span class="str">"a"</span>)) != NULL) </pre><pre class="alt"><span class="lnum">  53:  </span>            { </pre><pre><span class="lnum">  54:  </span>                    fprintf(fp, <span class="str">"%s\n"</span>, <span class="str">"test message"</span>); </pre><pre class="alt"><span class="lnum">  55:  </span>                    fclose(fp); </pre><pre><span class="lnum">  56:  </span>            } </pre><pre class="alt"><span class="lnum">  57:  </span>    } </pre><pre><span class="lnum">  58:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  59:  </span>    <span class="kwrd">return</span> 0;</pre><pre><span class="lnum">  60:  </span>}</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<h4>1.2 编写服务脚本</h4>
<p>参考链接<a href="http://blog.sina.com.cn/s/blog_57421ff80100c7nn.html">http://blog.sina.com.cn/s/blog_57421ff80100c7nn.html</a>
<p>红色字是需要填写的部分, 文件头部分可以选填
<div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span><span class="rem">#!/bin/bash</span></pre><pre><span class="lnum">   2:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   3:  </span><span class="rem"># chkconfig: 3 3 1</span></pre><pre><span class="lnum">   4:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   5:  </span><span class="rem"># description: web kill center</span></pre><pre><span class="lnum">   6:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   7:  </span>EXEC_PATH=/usr/<span class="kwrd">local</span>/bin</pre><pre><span class="lnum">   8:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">   9:  </span>EXEC=CenterServiced</pre><pre><span class="lnum">  10:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  11:  </span>PID_FILE=/var/run/CenterServiced.pid</pre><pre><span class="lnum">  12:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  13:  </span>DAEMON=/usr/<span class="kwrd">local</span>/bin/CenterServiced</pre><pre><span class="lnum">  14:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  15:  </span><span class="kwrd">if</span> ! [ -x $EXEC_PATH/$EXEC ] ; then</pre><pre><span class="lnum">  16:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  17:  </span>echo <span class="str">"ERROR: $EXEC_PATH/$EXEC not found"</span></pre><pre><span class="lnum">  18:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  19:  </span>exit 1</pre><pre><span class="lnum">  20:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  21:  </span>fi</pre><pre><span class="lnum">  22:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  23:  </span>stop()</pre><pre><span class="lnum">  24:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  25:  </span>{</pre><pre><span class="lnum">  26:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  27:  </span>echo <span class="str">"Stoping $EXEC ..."</span></pre><pre><span class="lnum">  28:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  29:  </span>killall $DAEMON &gt;/dev/null</pre><pre><span class="lnum">  30:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  31:  </span>echo <span class="str">"Shutting down $EXEC: [ OK ]"</span></pre><pre><span class="lnum">  32:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  33:  </span>}</pre><pre><span class="lnum">  34:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  35:  </span>start()</pre><pre><span class="lnum">  36:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  37:  </span>{</pre><pre><span class="lnum">  38:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  39:  </span>echo <span class="str">"Starting $EXEC ..."</span></pre><pre><span class="lnum">  40:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  41:  </span>$DAEMON &gt; /dev/null &amp;</pre><pre><span class="lnum">  42:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  43:  </span>echo <span class="str">"Starting $EXEC: [ OK ]"</span></pre><pre><span class="lnum">  44:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  45:  </span>}</pre><pre><span class="lnum">  46:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  47:  </span>restart()</pre><pre><span class="lnum">  48:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  49:  </span>{</pre><pre><span class="lnum">  50:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  51:  </span>stop</pre><pre><span class="lnum">  52:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  53:  </span>start</pre><pre><span class="lnum">  54:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  55:  </span>}</pre><pre><span class="lnum">  56:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  57:  </span>case <span class="str">"$1"</span> <span class="kwrd">in</span></pre><pre><span class="lnum">  58:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  59:  </span>start)</pre><pre><span class="lnum">  60:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  61:  </span>start</pre><pre><span class="lnum">  62:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  63:  </span>;;</pre><pre><span class="lnum">  64:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  65:  </span>stop)</pre><pre><span class="lnum">  66:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  67:  </span>stop</pre><pre><span class="lnum">  68:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  69:  </span>;;</pre><pre><span class="lnum">  70:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  71:  </span>restart)</pre><pre><span class="lnum">  72:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  73:  </span>restart</pre><pre><span class="lnum">  74:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  75:  </span>;;</pre><pre><span class="lnum">  76:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  77:  </span>status)</pre><pre><span class="lnum">  78:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  79:  </span>status -p $PID_FILE $DAEMON</pre><pre><span class="lnum">  80:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  81:  </span>;;</pre><pre><span class="lnum">  82:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  83:  </span>*)</pre><pre><span class="lnum">  84:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  85:  </span>echo <span class="str">"Usage: service $EXEC {start|stop|restart|status}"</span></pre><pre><span class="lnum">  86:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  87:  </span>exit 1</pre><pre><span class="lnum">  88:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  89:  </span>esac</pre><pre><span class="lnum">  90:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  91:  </span>exit $?</pre><pre><span class="lnum">  92:  </span>&nbsp;</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<h4>1.3 创建服务</h4>
<p>参考链接<a href="http://hi.baidu.com/guanxiansun/blog/item/b4c7dcf55f6011e47709d724.html">http://hi.baidu.com/guanxiansun/blog/item/b4c7dcf55f6011e47709d724.html</a>
<p>将服务文件拷贝到/etc/init.d下,去掉扩展名, 文件名即是服务名
<p>chmod +x ./wkcenter
<p>如果不设置启动, 那么service中将无法找到该服务及操作
<h4>1.4 设置启动顺序</h4>
<p>创建启动链接
<p>ln /etc/init.d/wkcenter /etc/rc3.d/S03wkcenter
<p>创建关闭链接
<p>ln /etc/init.d/wkcenter /etc/rc0.d/K03wkcenter
<h4>1.5 添加服务</h4>
<p>chkconfig --add wkcenter
<p>查看服务是否存在
<p>chkconfig –-list | grep wkcenter 
<p>查看服务状态
<p>chkconfig wkcenter on 
<p>注意, 确认wkcenter在2,3,4,5中任意或者部分开启, 必须为绿字. 灰字代表服务无法开机启动或者其他问题
<h4>1.6 测试</h4>
<p>临时开启命令测试
<p>service wkcenter start
<h4>1.7 QA</h4>
<p>参考链接: <a href="http://blog.526net.com/?p=1706">http://blog.526net.com/?p=1706</a>
<p>1. 服务切记不可放在用户home目录, 最好放在/usr/local/bin目录, 日志写到var中, 否则服务测试正常,但是无法自动启动
<p>2. Linux下, 父进程启动的程序的生命期跟随父进程, 父进程可以是终端, 父进程一旦终止, 子进程都必须结束. 因此守护进程需要脱离父进程,避免被父进程生命期控制

<img src ="http://www.cppblog.com/sunicdavy/aggbug/166680.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-28 10:52 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/28/166680.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>跨平台Unicode与UTF8互转代码</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/27/166623.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Mon, 27 Feb 2012 06:21:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/27/166623.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/166623.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/27/166623.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/166623.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/166623.html</trackback:ping><description><![CDATA[<p>参考来源:<a href="http://blog.csdn.net/flying8127/article/details/1598521">http://blog.csdn.net/flying8127/article/details/1598521</a></p> <p>在原来原基础上,将代码整理,并加强安全性. 并按照WindowsAPI设计, 添加输出缓冲长度探测功能</p> <p>当OutUTFString为NULL时, 可以进行输出的UTF8字符串长度探测</p> <div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>uint32 UniCharToUTF8(wchar_t UniChar, <span class="kwrd">char</span> *OutUTFString)</pre><pre><span class="lnum">   2:  </span>    {</pre><pre class="alt"><span class="lnum">   3:  </span>&nbsp;</pre><pre><span class="lnum">   4:  </span>        uint32 UTF8CharLength = 0;</pre><pre class="alt"><span class="lnum">   5:  </span>&nbsp;</pre><pre><span class="lnum">   6:  </span>        <span class="kwrd">if</span> (UniChar &lt; 0x80)</pre><pre class="alt"><span class="lnum">   7:  </span>        {  </pre><pre><span class="lnum">   8:  </span>            <span class="kwrd">if</span> ( OutUTFString )</pre><pre class="alt"><span class="lnum">   9:  </span>                OutUTFString[UTF8CharLength++] = (<span class="kwrd">char</span>)UniChar;</pre><pre><span class="lnum">  10:  </span>            <span class="kwrd">else</span></pre><pre class="alt"><span class="lnum">  11:  </span>                UTF8CharLength++;</pre><pre><span class="lnum">  12:  </span>        }</pre><pre class="alt"><span class="lnum">  13:  </span>        <span class="kwrd">else</span> <span class="kwrd">if</span>(UniChar &lt; 0x800)</pre><pre><span class="lnum">  14:  </span>        {</pre><pre class="alt"><span class="lnum">  15:  </span>            <span class="kwrd">if</span> ( OutUTFString )</pre><pre><span class="lnum">  16:  </span>            {</pre><pre class="alt"><span class="lnum">  17:  </span>                OutUTFString[UTF8CharLength++] = 0xc0 | ( UniChar &gt;&gt; 6 );</pre><pre><span class="lnum">  18:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( UniChar &amp; 0x3f );</pre><pre class="alt"><span class="lnum">  19:  </span>            }</pre><pre><span class="lnum">  20:  </span>            <span class="kwrd">else</span></pre><pre class="alt"><span class="lnum">  21:  </span>            {</pre><pre><span class="lnum">  22:  </span>                UTF8CharLength += 2;</pre><pre class="alt"><span class="lnum">  23:  </span>            }</pre><pre><span class="lnum">  24:  </span>        }</pre><pre class="alt"><span class="lnum">  25:  </span>        <span class="kwrd">else</span> <span class="kwrd">if</span>(UniChar &lt; 0x10000 )</pre><pre><span class="lnum">  26:  </span>        {</pre><pre class="alt"><span class="lnum">  27:  </span>            <span class="kwrd">if</span> ( OutUTFString )</pre><pre><span class="lnum">  28:  </span>            {</pre><pre class="alt"><span class="lnum">  29:  </span>                OutUTFString[UTF8CharLength++] = 0xe0 | ( UniChar &gt;&gt; 12 );</pre><pre><span class="lnum">  30:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( (UniChar &gt;&gt; 6) &amp; 0x3f );</pre><pre class="alt"><span class="lnum">  31:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( UniChar &amp; 0x3f );</pre><pre><span class="lnum">  32:  </span>            }</pre><pre class="alt"><span class="lnum">  33:  </span>            <span class="kwrd">else</span></pre><pre><span class="lnum">  34:  </span>            {</pre><pre class="alt"><span class="lnum">  35:  </span>                UTF8CharLength += 3;</pre><pre><span class="lnum">  36:  </span>            }</pre><pre class="alt"><span class="lnum">  37:  </span>        }</pre><pre><span class="lnum">  38:  </span>        <span class="kwrd">else</span> <span class="kwrd">if</span>( UniChar &lt; 0x200000 ) </pre><pre class="alt"><span class="lnum">  39:  </span>        {</pre><pre><span class="lnum">  40:  </span>            <span class="kwrd">if</span> ( OutUTFString )</pre><pre class="alt"><span class="lnum">  41:  </span>            {</pre><pre><span class="lnum">  42:  </span>                OutUTFString[UTF8CharLength++] = 0xf0 | ( (<span class="kwrd">int</span>)UniChar &gt;&gt; 18 );</pre><pre class="alt"><span class="lnum">  43:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( (UniChar &gt;&gt; 12) &amp; 0x3f );</pre><pre><span class="lnum">  44:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( (UniChar &gt;&gt; 6) &amp; 0x3f );</pre><pre class="alt"><span class="lnum">  45:  </span>                OutUTFString[UTF8CharLength++] = 0x80 | ( UniChar &amp; 0x3f );</pre><pre><span class="lnum">  46:  </span>            }</pre><pre class="alt"><span class="lnum">  47:  </span>            <span class="kwrd">else</span></pre><pre><span class="lnum">  48:  </span>            {</pre><pre class="alt"><span class="lnum">  49:  </span>                UTF8CharLength += 4;</pre><pre><span class="lnum">  50:  </span>            }</pre><pre class="alt"><span class="lnum">  51:  </span>&nbsp;</pre><pre><span class="lnum">  52:  </span>        }</pre><pre class="alt"><span class="lnum">  53:  </span>&nbsp;</pre><pre><span class="lnum">  54:  </span>        <span class="kwrd">return</span> UTF8CharLength;</pre><pre class="alt"><span class="lnum">  55:  </span>    }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>&nbsp;</p>
<p>当OutUnicodeString为NULL时, 可以进行输出的Unicode字符串长度探测</p>
<p>&nbsp;</p>
<div class="csharpcode"><pre class="alt"><span class="lnum">   1:  </span>uint32 UTF8StrToUnicode( <span class="kwrd">const</span> <span class="kwrd">char</span>* UTF8String, uint32 UTF8StringLength, wchar_t* OutUnicodeString, uint32 UnicodeStringBufferSize )</pre><pre><span class="lnum">   2:  </span>    {</pre><pre class="alt"><span class="lnum">   3:  </span>        uint32 UTF8Index = 0;</pre><pre><span class="lnum">   4:  </span>        uint32 UniIndex = 0;</pre><pre class="alt"><span class="lnum">   5:  </span>&nbsp;</pre><pre><span class="lnum">   6:  </span>        <span class="kwrd">while</span> ( UTF8Index &lt; UTF8StringLength )</pre><pre class="alt"><span class="lnum">   7:  </span>        {</pre><pre><span class="lnum">   8:  </span>            unsigned <span class="kwrd">char</span> UTF8Char = UTF8String[UTF8Index];</pre><pre class="alt"><span class="lnum">   9:  </span>&nbsp;</pre><pre><span class="lnum">  10:  </span>            <span class="kwrd">if</span> ( UnicodeStringBufferSize != 0 &amp;&amp; UniIndex &gt;= UnicodeStringBufferSize )</pre><pre class="alt"><span class="lnum">  11:  </span>                <span class="kwrd">break</span>;</pre><pre><span class="lnum">  12:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  13:  </span>            <span class="kwrd">if</span> ((UTF8Char &amp; 0x80) == 0) </pre><pre><span class="lnum">  14:  </span>            {</pre><pre class="alt"><span class="lnum">  15:  </span>                <span class="kwrd">const</span> uint32 cUTF8CharRequire = 1;</pre><pre><span class="lnum">  16:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  17:  </span>                <span class="rem">// UTF8字码不足</span></pre><pre><span class="lnum">  18:  </span>                <span class="kwrd">if</span> ( UTF8Index + cUTF8CharRequire &gt; UTF8StringLength )</pre><pre class="alt"><span class="lnum">  19:  </span>                    <span class="kwrd">break</span>;</pre><pre><span class="lnum">  20:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  21:  </span>                <span class="kwrd">if</span> ( OutUnicodeString )</pre><pre><span class="lnum">  22:  </span>                {</pre><pre class="alt"><span class="lnum">  23:  </span>                    wchar_t&amp; WideChar = OutUnicodeString[UniIndex]; </pre><pre><span class="lnum">  24:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  25:  </span>                    WideChar = UTF8Char;</pre><pre><span class="lnum">  26:  </span>                }</pre><pre class="alt"><span class="lnum">  27:  </span>&nbsp;</pre><pre><span class="lnum">  28:  </span>                UTF8Index++;</pre><pre class="alt"><span class="lnum">  29:  </span>                </pre><pre><span class="lnum">  30:  </span>            } </pre><pre class="alt"><span class="lnum">  31:  </span>            <span class="kwrd">else</span> <span class="kwrd">if</span>((UTF8Char &amp; 0xE0) == 0xC0)  <span class="rem">///&lt; 110x-xxxx 10xx-xxxx</span></pre><pre><span class="lnum">  32:  </span>            {</pre><pre class="alt"><span class="lnum">  33:  </span>                <span class="kwrd">const</span> uint32 cUTF8CharRequire = 2;</pre><pre><span class="lnum">  34:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  35:  </span>                <span class="rem">// UTF8字码不足</span></pre><pre><span class="lnum">  36:  </span>                <span class="kwrd">if</span> ( UTF8Index + cUTF8CharRequire &gt; UTF8StringLength )</pre><pre class="alt"><span class="lnum">  37:  </span>                    <span class="kwrd">break</span>;</pre><pre><span class="lnum">  38:  </span>&nbsp;</pre><pre class="alt"><span class="lnum">  39:  </span>                <span class="kwrd">if</span> ( OutUnicodeString )</pre><pre><span class="lnum">  40:  </span>                {</pre><pre class="alt"><span class="lnum">  41:  </span>                    wchar_t&amp; WideChar = OutUnicodeString[UniIndex]; </pre><pre><span class="lnum">  42:  </span>                    WideChar  = (UTF8String[UTF8Index + 0] &amp; 0x3F) &lt;&lt; 6;</pre><pre class="alt"><span class="lnum">  43:  </span>                    WideChar |= (UTF8String[UTF8Index + 1] &amp; 0x3F);</pre><pre><span class="lnum">  44:  </span>                }</pre><pre class="alt"><span class="lnum">  45:  </span>                </pre><pre><span class="lnum">  46:  </span>                UTF8Index += cUTF8CharRequire;</pre><pre class="alt"><span class="lnum">  47:  </span>            }</pre><pre><span class="lnum">  48:  </span>            <span class="kwrd">else</span> <span class="kwrd">if</span>((UTF8Char &amp; 0xF0) == 0xE0)  <span class="rem">///&lt; 1110-xxxx 10xx-xxxx 10xx-xxxx</span></pre><pre class="alt"><span class="lnum">  49:  </span>            {</pre><pre><span class="lnum">  50:  </span>                <span class="kwrd">const</span> uint32 cUTF8CharRequire = 3;</pre><pre class="alt"><span class="lnum">  51:  </span>&nbsp;</pre><pre><span class="lnum">  52:  </span>                <span class="rem">// UTF8字码不足</span></pre><pre class="alt"><span class="lnum">  53:  </span>                <span class="kwrd">if</span> ( UTF8Index + cUTF8CharRequire &gt; UTF8StringLength )</pre><pre><span class="lnum">  54:  </span>                    <span class="kwrd">break</span>;</pre><pre class="alt"><span class="lnum">  55:  </span>&nbsp;</pre><pre><span class="lnum">  56:  </span>                <span class="kwrd">if</span> ( OutUnicodeString )</pre><pre class="alt"><span class="lnum">  57:  </span>                {</pre><pre><span class="lnum">  58:  </span>                    wchar_t&amp; WideChar = OutUnicodeString[UniIndex]; </pre><pre class="alt"><span class="lnum">  59:  </span>&nbsp;</pre><pre><span class="lnum">  60:  </span>                    WideChar  = (UTF8String[UTF8Index + 0] &amp; 0x1F) &lt;&lt; 12;</pre><pre class="alt"><span class="lnum">  61:  </span>                    WideChar |= (UTF8String[UTF8Index + 1] &amp; 0x3F) &lt;&lt; 6;</pre><pre><span class="lnum">  62:  </span>                    WideChar |= (UTF8String[UTF8Index + 2] &amp; 0x3F);</pre><pre class="alt"><span class="lnum">  63:  </span>                }</pre><pre><span class="lnum">  64:  </span>                </pre><pre class="alt"><span class="lnum">  65:  </span>&nbsp;</pre><pre><span class="lnum">  66:  </span>                UTF8Index += cUTF8CharRequire;</pre><pre class="alt"><span class="lnum">  67:  </span>            } </pre><pre><span class="lnum">  68:  </span>            <span class="kwrd">else</span> <span class="kwrd">if</span>((UTF8Char &amp; 0xF8) == 0xF0)  <span class="rem">///&lt; 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx </span></pre><pre class="alt"><span class="lnum">  69:  </span>            {</pre><pre><span class="lnum">  70:  </span>                <span class="kwrd">const</span> uint32 cUTF8CharRequire = 4;</pre><pre class="alt"><span class="lnum">  71:  </span>&nbsp;</pre><pre><span class="lnum">  72:  </span>                <span class="rem">// UTF8字码不足</span></pre><pre class="alt"><span class="lnum">  73:  </span>                <span class="kwrd">if</span> ( UTF8Index + cUTF8CharRequire &gt; UTF8StringLength )</pre><pre><span class="lnum">  74:  </span>                    <span class="kwrd">break</span>;</pre><pre class="alt"><span class="lnum">  75:  </span>&nbsp;</pre><pre><span class="lnum">  76:  </span>                <span class="kwrd">if</span> ( OutUnicodeString )</pre><pre class="alt"><span class="lnum">  77:  </span>                {</pre><pre><span class="lnum">  78:  </span>                    wchar_t&amp; WideChar = OutUnicodeString[UniIndex]; </pre><pre class="alt"><span class="lnum">  79:  </span>&nbsp;</pre><pre><span class="lnum">  80:  </span>                    WideChar  = (UTF8String[UTF8Index + 0] &amp; 0x0F) &lt;&lt; 18;</pre><pre class="alt"><span class="lnum">  81:  </span>                    WideChar  = (UTF8String[UTF8Index + 1] &amp; 0x3F) &lt;&lt; 12;</pre><pre><span class="lnum">  82:  </span>                    WideChar |= (UTF8String[UTF8Index + 2] &amp; 0x3F) &lt;&lt; 6;</pre><pre class="alt"><span class="lnum">  83:  </span>                    WideChar |= (UTF8String[UTF8Index + 3] &amp; 0x3F);</pre><pre><span class="lnum">  84:  </span>                }</pre><pre class="alt"><span class="lnum">  85:  </span>&nbsp;</pre><pre><span class="lnum">  86:  </span>                UTF8Index += cUTF8CharRequire;</pre><pre class="alt"><span class="lnum">  87:  </span>            } </pre><pre><span class="lnum">  88:  </span>            <span class="kwrd">else</span> <span class="rem">///&lt; 1111-10xx 10xx-xxxx 10xx-xxxx 10xx-xxxx 10xx-xxxx </span></pre><pre class="alt"><span class="lnum">  89:  </span>            {</pre><pre><span class="lnum">  90:  </span>                <span class="kwrd">const</span> uint32 cUTF8CharRequire = 5;</pre><pre class="alt"><span class="lnum">  91:  </span>&nbsp;</pre><pre><span class="lnum">  92:  </span>                <span class="rem">// UTF8字码不足</span></pre><pre class="alt"><span class="lnum">  93:  </span>                <span class="kwrd">if</span> ( UTF8Index + cUTF8CharRequire &gt; UTF8StringLength )</pre><pre><span class="lnum">  94:  </span>                    <span class="kwrd">break</span>;</pre><pre class="alt"><span class="lnum">  95:  </span>&nbsp;</pre><pre><span class="lnum">  96:  </span>                <span class="kwrd">if</span> ( OutUnicodeString )</pre><pre class="alt"><span class="lnum">  97:  </span>                {</pre><pre><span class="lnum">  98:  </span>                    wchar_t&amp; WideChar = OutUnicodeString[UniIndex]; </pre><pre class="alt"><span class="lnum">  99:  </span>&nbsp;</pre><pre><span class="lnum"> 100:  </span>                    WideChar  = (UTF8String[UTF8Index + 0] &amp; 0x07) &lt;&lt; 24;</pre><pre class="alt"><span class="lnum"> 101:  </span>                    WideChar  = (UTF8String[UTF8Index + 1] &amp; 0x3F) &lt;&lt; 18;</pre><pre><span class="lnum"> 102:  </span>                    WideChar  = (UTF8String[UTF8Index + 2] &amp; 0x3F) &lt;&lt; 12;</pre><pre class="alt"><span class="lnum"> 103:  </span>                    WideChar |= (UTF8String[UTF8Index + 3] &amp; 0x3F) &lt;&lt; 6;</pre><pre><span class="lnum"> 104:  </span>                    WideChar |= (UTF8String[UTF8Index + 4] &amp; 0x3F);</pre><pre class="alt"><span class="lnum"> 105:  </span>                }</pre><pre><span class="lnum"> 106:  </span>&nbsp;</pre><pre class="alt"><span class="lnum"> 107:  </span>                UTF8Index += cUTF8CharRequire;</pre><pre><span class="lnum"> 108:  </span>            }</pre><pre class="alt"><span class="lnum"> 109:  </span>&nbsp;</pre><pre><span class="lnum"> 110:  </span>&nbsp;</pre><pre class="alt"><span class="lnum"> 111:  </span>            UniIndex++;</pre><pre><span class="lnum"> 112:  </span>        }</pre><pre class="alt"><span class="lnum"> 113:  </span>&nbsp;</pre><pre><span class="lnum"> 114:  </span>        <span class="kwrd">return</span> UniIndex;</pre><pre class="alt"><span class="lnum"> 115:  </span>    }</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>疗效: 用了此代码啊, 再也不用被iconv折磨了</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/166623.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-27 14:21 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/27/166623.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux/Windows下hash_map的表现差异</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/23/166353.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Thu, 23 Feb 2012 10:54:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/23/166353.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/166353.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/23/166353.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/166353.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/166353.html</trackback:ping><description><![CDATA[<p>hash_map不是标准库,因此不同平台下包含头文件不同, 前缀也不同,这里使用了一个通用定义</p> <div class="csharpcode"><pre><span class="lnum">   1:  </span>#ifdef _WIN32</pre><pre><span class="lnum">   2:  </span>    #include &lt;hash_map&gt;</pre><pre><span class="lnum">   3:  </span>    <span class="preproc">#define</span> HASHMAP_PREFIX stdext</pre><pre><span class="lnum">   4:  </span><span class="preproc">#else</span></pre><pre><span class="lnum">   5:  </span>    #include &lt;ext/hash_map&gt;</pre><pre><span class="lnum">   6:  </span>    <span class="preproc">#define</span> HASHMAP_PREFIX __gnu_cxx    </pre><pre><span class="lnum">   7:  </span><span class="preproc">#endif</span></pre></div>
<p>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>
</p>
<p>对于初始桶大小设置,Linux下使用hash_map构造函数可以设置, Windows下则没有对应的设置函数.</p>
<p>查阅Windows下hash_map的源码,并在hash_map()默认构造函数旁边添加一个测试用初始桶设置函数</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span>    hash_map( size_type _Buckets )</pre></div>
<div class="csharpcode"><pre><span class="lnum">   2:  </span>        : _Mybase(key_compare(), allocator_type())</pre></div>
<div class="csharpcode"><pre><span class="lnum">   3:  </span>    {</pre></div>
<div class="csharpcode"><pre><span class="lnum">   4:  </span>        _Init( _Buckets );</pre></div>
<div class="csharpcode"><pre><span class="lnum">   5:  </span>    }</pre></div>
<blockquote>
</blockquote>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>

<p>接下来使用相同的测试代码</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span>    <span class="kwrd">const</span> uint32 Buckets = 1000;</pre><pre><span class="lnum">   2:  </span>    HASHMAP_PREFIX::hash_map&lt;uint32,uint32&gt; MyHash( Buckets );</pre><pre><span class="lnum">   3:  </span>&nbsp;</pre><pre><span class="lnum">   4:  </span>    TimeRuler Ruler;</pre><pre><span class="lnum">   5:  </span>    <span class="kwrd">for</span> ( uint32 i = 0; i &lt;1000000;i++)</pre><pre><span class="lnum">   6:  </span>    {</pre><pre><span class="lnum">   7:  </span>        MyHash[i] = i;</pre><pre><span class="lnum">   8:  </span>    }</pre><pre><span class="lnum">   9:  </span>&nbsp;</pre><pre><span class="lnum">  10:  </span>    printf(<span class="str">"%d\n"</span>, Ruler.GetCostTime() );</pre></div>
<style type="text/css">.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</style>


<p>这里的TimeRuler是使用boost timer的时间戳封装</p>
<p>Release下测试结果:</p>
<table style="color: #000000" border="0" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp; OS \ Buckets</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8 ( default )</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1000 </td></tr>
<tr>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp; Win7</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 430ms</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 560ms</td></tr>
<tr>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp; Mint( VMware )</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 127ms</td>
<td valign="top" width="133">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 127ms</td></tr></tbody></table>
<p>&nbsp;</p>
<p>Windows的测试结果说明, 不给出桶初始化函数是正确的, 默认管理比自己设置更高效. </p>
<p>Linux平台感觉很诡异, 不清楚是不是虚拟机造成的结果不准确</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/166353.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-23 18:54 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/23/166353.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>luabind的正确完整编译法</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/21/166118.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Tue, 21 Feb 2012 03:23:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/21/166118.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/166118.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/21/166118.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/166118.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/166118.html</trackback:ping><description><![CDATA[<p>之前看了网上一篇<a href="http://hi.baidu.com/koangel/blog/item/8375693d0fc6fddd9f3d62c5.html">文章</a>介绍luabind, 发现这种编译出来的luabind只会安装debug版本, release版本的so依然坦然的躺在工程目录</p> <p>查阅bjam的参数说明及luabind的jamroot文件第240行有如下文字</p> <p>install stage<br />&nbsp; : luabind<br />&nbsp; : &lt;location&gt;$(stage-locate)<br />&nbsp;&nbsp;&nbsp; &lt;install-no-version-symlinks&gt;on<br />&nbsp;&nbsp;&nbsp; &lt;install-dependencies&gt;on<br />&nbsp;&nbsp;&nbsp; &lt;install-type&gt;LIB<br />&nbsp; ;</p> <p>说明参数应该是这样的: bjam install [stage]</p> <p>而且文章中给出的是bjam install 因此默认出调试版也是正确的, 而且估计作者只编译了调试版就没有处理release版了</p> <p>正确的luabind编译法应该是:</p> <p>export BOOST_ROOT=/home/davy/dev/boost_1_48_0 </p><p>export LUA_PATH=/usr/local/ </p><p>/home/davy/dev/boost_1_48_0/bjam stage --toolset=gcc --with-date_time --with-fpic --with-filesystem link=static debug release<span style="font-family: 'Lucida Console'; font-size: 10.5pt; "><br /></span></p><p>/home/davy/dev/boost_1_48_0/bjam install debug </p><p>/home/davy/dev/boost_1_48_0/bjam install release </p><p>&nbsp; </p><p>我这里必须指明bjam是因为boost的bjam版本高于默认安装的版本, 因此使用高版本编译  </p><img src ="http://www.cppblog.com/sunicdavy/aggbug/166118.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-21 11:23 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/21/166118.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux在VMware中网络设置</title><link>http://www.cppblog.com/sunicdavy/archive/2012/02/04/164934.html</link><dc:creator>战魂小筑</dc:creator><author>战魂小筑</author><pubDate>Sat, 04 Feb 2012 03:41:00 GMT</pubDate><guid>http://www.cppblog.com/sunicdavy/archive/2012/02/04/164934.html</guid><wfw:comment>http://www.cppblog.com/sunicdavy/comments/164934.html</wfw:comment><comments>http://www.cppblog.com/sunicdavy/archive/2012/02/04/164934.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/sunicdavy/comments/commentRss/164934.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/sunicdavy/services/trackbacks/164934.html</trackback:ping><description><![CDATA[<p>这里使用的是Ubuntu的最流行发行版Mint, 其他版本类似</p> <p>以下将虚拟机内系统叫Guest, 运行VMWare的系统叫Host</p> <p>将VMWare的网络方式设为Bridge模式. 注意Host-Only模式只能与Host连接,局域网的机器及互联网机器无法访问</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_6.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_thumb_2.png" width="306" height="276"></a></p> <p>在Guest的网络设置中,将IP设置为与Host在一个局域网网段的IP, 设置DNS</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_4.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_thumb_1.png" width="402" height="292"></a></p> <p>关闭Guest系统</p> <p>接下来将Host的可以上网的连接添加共享,并连接到VMNet1</p> <p><a href="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://www.cppblog.com/images/cppblog_com/sunicdavy/Windows-Live-Writer/Linux-VMware_A07B/image_thumb.png" width="599" height="232"></a></p> <p>进入Guest系统, 测试上网</p><img src ="http://www.cppblog.com/sunicdavy/aggbug/164934.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/sunicdavy/" target="_blank">战魂小筑</a> 2012-02-04 11:41 <a href="http://www.cppblog.com/sunicdavy/archive/2012/02/04/164934.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>