??xml version="1.0" encoding="utf-8" standalone="yes"?>国内精品伊人久久久久,久久人人爽人人爽人人片av高请,国产69精品久久久久久人妻精品http://www.shnenglu.com/API/category/20757.htmlzh-cnThu, 07 May 2020 14:46:01 GMTThu, 07 May 2020 14:46:01 GMT60origin游戏服务器引擎介l?/title><link>http://www.shnenglu.com/API/archive/2020/05/07/217287.html</link><dc:creator>C++技术中?/dc:creator><author>C++技术中?/author><pubDate>Thu, 07 May 2020 08:06:00 GMT</pubDate><guid>http://www.shnenglu.com/API/archive/2020/05/07/217287.html</guid><wfw:comment>http://www.shnenglu.com/API/comments/217287.html</wfw:comment><comments>http://www.shnenglu.com/API/archive/2020/05/07/217287.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/API/comments/commentRss/217287.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/API/services/trackbacks/217287.html</trackback:ping><description><![CDATA[<div>origin 游戏服务器引擎简?/div><div>==================</div><div></div><div></div><div>origin 是一个由 Go 语言QgolangQ编写的分布式开源游戏服务器引擎。origin适用于各cL戏服务器的开发,包括 H5QHTML5Q游戏服务器?/div><div></div><div>origin 解决的问题:</div><div>* originM设计如go语言设计一PL可能的提供z和易用的模式,快速开发?/div><div>* 能够Ҏ业务需求快速ƈ灉|的制定服务器架构?/div><div>* 利用多核优势Q将不同的service配置C同的nodeQƈ能高效的协同工作?/div><div>* 整个引擎抽象三大对象,node,service,module。通过l一的组合模型管理游戏中各功能模块的关系?/div><div>* 有丰富ƈ健壮的工具库?/div><div></div><div>Hello world!</div><div>---------------</div><div>下面我们来一步步的徏立origin服务?先下载[origin引擎](https://github.com/duanhf2012/origin "origin引擎"),或者用如下命令:</div><div>```go</div><div>go get -v -u  github.com/duanhf2012/origin</div><div>```</div><div>于是下蝲到GOPATH环境目录?在src中加入main.go,内容如下Q?/div><div>```go</div><div>package main</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div>)</div><div></div><div>func main() {</div><div><span style="white-space:pre"> </span>node.Start()</div><div>}</div><div>```</div><div>一个originq程需要创Z个node对象,Start开始运行。您也可以直接下载origin引擎CZ:</div><div>```</div><div>go get -v -u github.com/duanhf2012/originserver</div><div>```</div><div>本文所有的说明都是Z该示例ؓ丅R?/div><div></div><div>origin引擎三大对象关系</div><div>---------------</div><div>* Node:   可以认ؓ每一个Node代表着一个originq程</div><div>* Service:一个独立的服务可以认ؓ是一个大的功能模块,他是Node的子集,创徏完成q安装Node对象中。服务可以支持对外部RPC{功能?/div><div>* Module: q是origin最对象单元,强烈所有的业务模块都划分成各个的Modulel合Qorigin引擎监控所有服务与Moduleq行状态,例如可以监控它们的慢处理和死循环函数。Module可以建立树状关系。Service本n也是Module的类型?/div><div></div><div>origin集群核心配置文g在config的cluster目录下,在cluster下有子网目录Q如github.com/duanhf2012/originserver的config/cluster目录下有subnet目录Q表C子|名为subnetQ可以新加多个子|的目录配置。子|与子网间是隔离的,后箋支持子|间通信规则Qorigin集群配置以子|的模式配置Q在每个子网下配|多个Node服务?子网在应对复杂的pȝ时可以应用到各个子系l,方便每个子系l的隔离。在CZ的subnet目录中有cluster.json与service.json配置Q?/div><div></div><div>cluster.json如下Q?/div><div>---------------</div><div>```</div><div>{</div><div>    "NodeList":[</div><div>        {</div><div>          "NodeId": 1,</div><div>          "ListenAddr":"127.0.0.1:8001",</div><div>          "NodeName": "Node_Test1",</div><div><span style="white-space:pre"> </span>  "remark":"http://以_打头的,表示只在本机q程Q不Ҏ个子|开?,</div><div>          "ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","_TcpService","HttpService","WSService"]</div><div>        },</div><div><span style="white-space:pre"> </span> {</div><div>          "NodeId": 2,</div><div>          "ListenAddr":"127.0.0.1:8002",</div><div>          "NodeName": "Node_Test1",</div><div><span style="white-space:pre"> </span>  "remark":"http://以_打头的,表示只在本机q程Q不Ҏ个子|开?,</div><div>          "ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","TcpService","HttpService","WSService"]</div><div>        }</div><div>    ]</div><div>```</div><div>---------------</div><div>以上配置了两个结Ҏ务器E序:</div><div>* NodeId: 表示originE序的结点Id标识Q不允许重复?/div><div>* ListenAddr:Rpc通信服务的监听地址</div><div>* NodeName:l点名称</div><div>* remark:备注Q可选项</div><div>* ServiceList:该Node安装的服务列表</div><div>---------------</div><div></div><div>在启动程序命令program start nodeid=1中nodeid是Ҏ该配|装载服务?/div><div>service.json如下Q?/div><div>---------------</div><div>```</div><div>{</div><div>  "Service":{</div><div><span style="white-space:pre"> </span>  "HttpService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9402",</div><div><span style="white-space:pre"> </span>"ReadTimeout":10000,</div><div><span style="white-space:pre"> </span>"WriteTimeout":10000,</div><div><span style="white-space:pre"> </span>"ProcessTimeout":10000,</div><div><span style="white-space:pre"> </span>"CAFile":[</div><div><span style="white-space:pre"> </span>{</div><div><span style="white-space:pre"> </span>"Certfile":"",</div><div><span style="white-space:pre"> </span>"Keyfile":""</div><div><span style="white-space:pre"> </span>}</div><div><span style="white-space:pre"> </span>]</div><div><span style="white-space:pre"> </span></div><div><span style="white-space:pre"> </span>  },</div><div><span style="white-space:pre"> </span>  "TcpService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9030",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"LittleEndian":false,</div><div><span style="white-space:pre"> </span>"MinMsgLen":4,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  },</div><div><span style="white-space:pre"> </span>  "WSService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  }  </div><div>  },</div><div>  "NodeService":[</div><div>   {</div><div>      "NodeId":1,</div><div><span style="white-space:pre"> </span>  "TcpService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9830",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"LittleEndian":false,</div><div><span style="white-space:pre"> </span>"MinMsgLen":4,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  },</div><div><span style="white-space:pre"> </span>  "WSService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  }  </div><div>   },</div><div>   {</div><div>      "NodeId":2,</div><div><span style="white-space:pre"> </span>  "TcpService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9030",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"LittleEndian":false,</div><div><span style="white-space:pre"> </span>"MinMsgLen":4,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  },</div><div><span style="white-space:pre"> </span>  "WSService":{</div><div><span style="white-space:pre"> </span>"ListenAddr":"0.0.0.0:9031",</div><div><span style="white-space:pre"> </span>"MaxConnNum":3000,</div><div><span style="white-space:pre"> </span>"PendingWriteNum":10000,</div><div><span style="white-space:pre"> </span>"MaxMsgLen":65535</div><div><span style="white-space:pre"> </span>  }  </div><div>   }</div><div>  ]</div><div> </div><div>}</div><div>```</div><div></div><div>---------------</div><div>以上配置分ؓ两个部分QService与NodeServiceQNodeService中配|的对应l点中服务的配置Q如果启动程序中Ҏnodeid查找该域的对应的服务Q如果找不到Ӟ从Service公共部分查找?/div><div></div><div>**HttpService配置**</div><div>* ListenAddr:Http监听地址</div><div>* ReadTimeout:ȝl超时毫U?/div><div>* WriteTimeout:写网l超时毫U?/div><div>* ProcessTimeout: 处理时毫秒</div><div>* CAFile: 证书文gQ如果您的服务器通过web服务器代理配|https可以忽略该配|?/div><div></div><div>**TcpService配置**</div><div>* ListenAddr: 监听地址</div><div>* MaxConnNum: 允许最大连接数</div><div>* PendingWriteNumQ发送网l队列最大数?/div><div>* LittleEndian:是否端</div><div>* MinMsgLen:包最长?/div><div>* MaxMsgLen:包最大长?/div><div></div><div>**WSService配置**</div><div>* ListenAddr: 监听地址</div><div>* MaxConnNum: 允许最大连接数</div><div>* PendingWriteNumQ发送网l队列最大数?/div><div>* MaxMsgLen:包最大长?/div><div>---------------</div><div></div><div></div><div></div><div></div><div>W一章:origin基础:</div><div>---------------</div><div>查看github.com/duanhf2012/originserver中的simple_service中新Z个服务,分别是TestService1.go与CTestService2.go?/div><div></div><div>simple_service/TestService1.go如下Q?/div><div>```</div><div>package simple_service</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>//模块加蝲时自动安装TestService1服务</div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService1{})</div><div>}</div><div></div><div>//新徏自定义服务TestService1</div><div>type TestService1 struct {</div><div></div><div><span style="white-space:pre"> </span>//所有的自定义服务必需加入service.Service基服?/div><div><span style="white-space:pre"> </span>//那么该自定义服务有各种功能Ҏ?/div><div><span style="white-space:pre"> </span>//例如: Rpc,事g驱动,定时器等</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>//服务初始化函敎ͼ在安装服务时Q服务将自动调用OnInit函数</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div></div><div>```</div><div>simple_service/TestService2.go如下Q?/div><div>```</div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService2{})</div><div>}</div><div></div><div>type TestService2 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div></div><div>```</div><div></div><div>* main.goq行代码</div><div></div><div>```go</div><div>package main</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>//导入simple_service模块</div><div><span style="white-space:pre"> </span>_"orginserver/simple_service"</div><div>)</div><div></div><div>func main(){</div><div><span style="white-space:pre"> </span>node.Start()</div><div>}</div><div></div><div>```</div><div></div><div>* config/cluster/subnet/cluster.json如下Q?/div><div>```</div><div>{</div><div>    "NodeList":[</div><div>        {</div><div>          "NodeId": 1,</div><div>          "ListenAddr":"127.0.0.1:8001",</div><div>          "NodeName": "Node_Test1",</div><div><span style="white-space:pre"> </span>  "remark":"http://以_打头的,表示只在本机q程Q不Ҏ个子|开?,</div><div>          "ServiceList": ["TestService1","TestService2"]</div><div>        }</div><div>    ]</div><div>}</div><div>```</div><div></div><div>~译后运行结果如下:</div><div>```</div><div>#originserver start nodeid=1</div><div>TestService1 OnInit.</div><div>TestService2 OnInit.</div><div>```</div><div></div><div>W二章:Service中常用功?</div><div>---------------</div><div></div><div>定时?</div><div>---------------</div><div>在开发中最常用的功能有定时dQorigin提供两种定时方式Q?/div><div></div><div>一UAfterFunc函数Q可以间隔一定时间触发回调,参照simple_service/TestService2.go,实现如下Q?/div><div>```</div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre"> </span>fmt.Printf("TestService2 OnInit.\n")</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*1,slf.OnSecondTick)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestService2) OnSecondTick(){</div><div><span style="white-space:pre"> </span>fmt.Printf("tick.\n")</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*1,slf.OnSecondTick)</div><div>}</div><div>```</div><div>此时日志可以看到每隔1U钟会print一?tick."Q如果下ơ还需要触发,需要重新设|定时器</div><div></div><div></div><div>另一U方式是cMLinuxpȝ的crontab命oQ用如下:</div><div>```</div><div></div><div>func (slf *TestService2) OnInit() error {</div><div><span style="white-space:pre"> </span>fmt.Printf("TestService2 OnInit.\n")</div><div></div><div><span style="white-space:pre"> </span>//crontab模式定时触发</div><div><span style="white-space:pre"> </span>//NewCronExpr的参数分别代?Seconds Minutes Hours DayOfMonth Month DayOfWeek</div><div><span style="white-space:pre"> </span>//以下为每换分钟时触发</div><div><span style="white-space:pre"> </span>cron,_:=timer.NewCronExpr("0 * * * * *")</div><div><span style="white-space:pre"> </span>slf.CronFunc(cron,slf.OnCron)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div></div><div>func (slf *TestService2) OnCron(){</div><div><span style="white-space:pre"> </span>fmt.Printf(":A minute passed!\n")</div><div>}</div><div>```</div><div>以上q行l果每换分钟时打?A minute passed!</div><div></div><div></div><div>打开多协E模?</div><div>---------------</div><div>在origin引擎设计中,所有的服务是单协程模式Q这样在~写逻辑代码Ӟ不用考虑U程安全问题。极大的减少开发难度,但某些开发场景下不用考虑q个问题Q而且需要ƈ发执行的情况Q比如,某服务只处理数据库操作控Ӟ而数据库处理中发生阻塞等待的问题Q因Z个协E,该服务接受的数据库操作只能是一?/div><div>一个的排队处理Q效率过低。于是可以打开此模式指定处理协E数Q代码如下:</div><div>```</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre"> </span>fmt.Printf("TestService1 OnInit.\n")</div><div><span style="white-space:pre"> </span></div><div><span style="white-space:pre"> </span>//打开多线E处理模式,10个协Eƈ发处?/div><div><span style="white-space:pre"> </span>slf.SetGoRouterNum(10)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div>```</div><div>Z</div><div></div><div></div><div>性能监控功能:</div><div>---------------</div><div>我们在开发一个大型的pȝӞl常׃一些代码质量的原因Q生处理过慢或者死循环的生,该功能可以被监测到。用方法如下:</div><div></div><div>```</div><div>func (slf *TestService1) OnInit() error {</div><div><span style="white-space:pre"> </span>fmt.Printf("TestService1 OnInit.\n")</div><div><span style="white-space:pre"> </span>//打开性能分析工具</div><div><span style="white-space:pre"> </span>slf.OpenProfiler()</div><div><span style="white-space:pre"> </span>//监控过1U的慢处?/div><div><span style="white-space:pre"> </span>slf.GetProfiler().SetOverTime(time.Second*1)</div><div><span style="white-space:pre"> </span>//监控过10U的慢处理Q您可以用它来定位是否存在死循环</div><div><span style="white-space:pre"> </span>//比如以下讄10U,我的应用中是不会发生过10U的一ơ函数调?/div><div><span style="white-space:pre"> </span>//所以设|ؓ10U?/div><div><span style="white-space:pre"> </span>slf.GetProfiler().SetMaxOverTime(time.Second*10)</div><div></div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*2,slf.Loop)</div><div><span style="white-space:pre"> </span>//打开多线E处理模式,10个协Eƈ发处?/div><div><span style="white-space:pre"> </span>//slf.SetGoRouterNum(10)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestService1) Loop(){</div><div><span style="white-space:pre"> </span>for {</div><div><span style="white-space:pre"> </span>time.Sleep(time.Second*1)</div><div><span style="white-space:pre"> </span>}</div><div>}</div><div></div><div></div><div>func main(){</div><div><span style="white-space:pre"> </span>//打开性能分析报告功能Qƈ讄10U汇报一?/div><div><span style="white-space:pre"> </span>node.OpenProfilerReport(time.Second*10)</div><div><span style="white-space:pre"> </span>node.Start()</div><div>}</div><div></div><div>```</div><div>上面通过GetProfiler().SetOverTime与slf.GetProfiler().SetMaxOverTimer讄监控旉</div><div>q在main.go中,打开了性能报告器,以每10U汇报一ơ,因ؓ上面的例子中Q定时器是有d@环,所以可以得C下报告:</div><div></div><div>2020/04/22 17:53:30 profiler.go:179: [release] Profiler report tag TestService1:</div><div>process count 0,take time 0 Milliseconds,average 0 Milliseconds/per.</div><div>too slow process:Timer_orginserver/simple_service.(*TestService1).Loop-fm is take 38003 Milliseconds</div><div>直接帮助扑ֈTestService1服务中的Loop函数</div><div></div><div></div><div></div><div>W三章:Module使用:</div><div>---------------</div><div></div><div>Module创徏与销?</div><div>---------------</div><div>可以认ؓService是一UModuleQ它有Module所有的功能。在CZ代码中可以参考originserver/simple_module/TestService3.go?/div><div>```</div><div>package simple_module</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"fmt"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService3{})</div><div>}</div><div></div><div>type TestService3 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>type Module1 struct {</div><div><span style="white-space:pre"> </span>service.Module</div><div>}</div><div></div><div>type Module2 struct {</div><div><span style="white-space:pre"> </span>service.Module</div><div>}</div><div></div><div>func (slf *Module1) OnInit()error{</div><div><span style="white-space:pre"> </span>fmt.Printf("Module1 OnInit.\n")</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *Module1) OnRelease(){</div><div><span style="white-space:pre"> </span>fmt.Printf("Module1 Release.\n")</div><div>}</div><div></div><div>func (slf *Module2) OnInit()error{</div><div><span style="white-space:pre"> </span>fmt.Printf("Module2 OnInit.\n")</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *Module2) OnRelease(){</div><div><span style="white-space:pre"> </span>fmt.Printf("Module2 Release.\n")</div><div>}</div><div></div><div></div><div>func (slf *TestService3) OnInit() error {</div><div><span style="white-space:pre"> </span>//新徏两个Module对象</div><div><span style="white-space:pre"> </span>module1 := &Module1{}</div><div><span style="white-space:pre"> </span>module2 := &Module2{}</div><div><span style="white-space:pre"> </span>//module1d到服务中</div><div><span style="white-space:pre"> </span>module1Id,_ := slf.AddModule(module1)</div><div><span style="white-space:pre"> </span>//在module1中添加module2模块</div><div><span style="white-space:pre"> </span>module1.AddModule(module2)</div><div><span style="white-space:pre"> </span>fmt.Printf("module1 id is %d, module2 id is %d",module1Id,module2.GetModuleId())</div><div></div><div><span style="white-space:pre"> </span>//释放模块module1</div><div><span style="white-space:pre"> </span>slf.ReleaseModule(module1Id)</div><div><span style="white-space:pre"> </span>fmt.Printf("xxxxxxxxxxx")</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>```</div><div>在OnInit中创Z一条线型的模块关系TestService3->module1->module2Q调用AddModule后会q回Module的IdQ自动生成的Id?0e17开?内部的idQ您可以自己讄Id。当调用ReleaseModule释放时module1Ӟ同样会将module2释放。会自动调用OnRelease函数Q日志顺序如下:</div><div>```</div><div>Module1 OnInit.</div><div>Module2 OnInit.</div><div>module1 id is 100000000000000001, module2 id is 100000000000000002</div><div>Module2 Release.</div><div>Module1 Release.</div><div>```</div><div>在Module中同样可以用定时器功能Q请参照W二章节的定时器部分?/div><div></div><div></div><div>W四章:事g使用</div><div>---------------</div><div>事g是origin中一个重要的l成部分Q可以在同一个node中的service与service或者与module之间q行事g通知。系l内|的几个服务Q如QTcpService/HttpService{都是通过事g功能实现。他也是一个典型的观察者设计模型。在event中有两个cd的interfaceQ一个是event.IEventProcessor它提供注册与卸蝲功能Q另一个是event.IEventHandler提供消息q播{功能?/div><div></div><div>在目录simple_event/TestService4.go?/div><div>```</div><div>package simple_event</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/event"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre"> </span>"time"</div><div>)</div><div></div><div>const (</div><div><span style="white-space:pre"> </span>//自定义事件类型,必需从event.Sys_Event_User_Define开?/div><div><span style="white-space:pre"> </span>//event.Sys_Event_User_Define以内l系l预?/div><div><span style="white-space:pre"> </span>EVENT1 event.EventType =event.Sys_Event_User_Define+1</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService4{})</div><div>}</div><div></div><div>type TestService4 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>func (slf *TestService4) OnInit() error {</div><div><span style="white-space:pre"> </span>//10U后触发q播事g</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*10,slf.TriggerEvent)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestService4) TriggerEvent(){</div><div><span style="white-space:pre"> </span>//q播事gQ传入event.Event对象Q类型ؓEVENT1,Data可以自定义Q何数?/div><div><span style="white-space:pre"> </span>//q样Q所有监听者都可以收到该事?/div><div><span style="white-space:pre"> </span>slf.GetEventHandler().NotifyEvent(&event.Event{</div><div><span style="white-space:pre"> </span>Type: EVENT1,</div><div><span style="white-space:pre"> </span>Data: "event data.",</div><div><span style="white-space:pre"> </span>})</div><div>}</div><div></div><div></div><div>```</div><div></div><div>在目录simple_event/TestService5.go?/div><div>```</div><div>package simple_event</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"fmt"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/event"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService5{})</div><div>}</div><div></div><div>type TestService5 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>type TestModule struct {</div><div><span style="white-space:pre"> </span>service.Module</div><div>}</div><div></div><div>func (slf *TestModule) OnInit() error{</div><div><span style="white-space:pre"> </span>//在当前node中查找TestService4</div><div><span style="white-space:pre"> </span>pService := node.GetService("TestService4")</div><div></div><div><span style="white-space:pre"> </span>//在TestModule中,往TestService4中注册EVENT1cd事g监听</div><div><span style="white-space:pre"> </span>pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnModuleEvent)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestModule) OnModuleEvent(ev *event.Event){</div><div><span style="white-space:pre"> </span>fmt.Printf("OnModuleEvent type :%d data:%+v\n",ev.Type,ev.Data)</div><div>}</div><div></div><div></div><div>//服务初始化函敎ͼ在安装服务时Q服务将自动调用OnInit函数</div><div>func (slf *TestService5) OnInit() error {</div><div><span style="white-space:pre"> </span>//通过服务名获取服务对?/div><div><span style="white-space:pre"> </span>pService := node.GetService("TestService4")</div><div></div><div><span style="white-space:pre"> </span>////在TestModule中,往TestService4中注册EVENT1cd事g监听</div><div><span style="white-space:pre"> </span>pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnServiceEvent)</div><div><span style="white-space:pre"> </span>slf.AddModule(&TestModule{})</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestService5) OnServiceEvent(ev *event.Event){</div><div><span style="white-space:pre"> </span>fmt.Printf("OnServiceEvent type :%d data:%+v\n",ev.Type,ev.Data)</div><div>}</div><div></div><div></div><div>```</div><div>E序q行10U后Q调用slf.TriggerEvent函数q播事gQ于是在TestService5中会收到</div><div>```</div><div>OnServiceEvent type :1001 data:event data.</div><div>OnModuleEvent type :1001 data:event data.</div><div>```</div><div>在上面的TestModule中监听的事情Q当q个Module被Release时监听会自动卸蝲?/div><div></div><div>W五章:RPC使用</div><div>---------------</div><div>RPC是service与service间通信的重要方式,它允许跨q程node互相讉KQ当然也可以指定nodeidq行调用。如下示例:</div><div></div><div>simple_rpc/TestService6.go文g如下Q?/div><div>```</div><div>package simple_rpc</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService6{})</div><div>}</div><div></div><div>type TestService6 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>func (slf *TestService6) OnInit() error {</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>type InputData struct {</div><div><span style="white-space:pre"> </span>A int</div><div><span style="white-space:pre"> </span>B int</div><div>}</div><div></div><div>func (slf *TestService6) RPC_Sum(input *InputData,output *int) error{</div><div><span style="white-space:pre"> </span>*output = input.A+input.B</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>```</div><div></div><div>simple_rpc/TestService7.go文g如下Q?/div><div>```</div><div>package simple_rpc</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"fmt"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre"> </span>"time"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&TestService7{})</div><div>}</div><div></div><div>type TestService7 struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>func (slf *TestService7) OnInit() error {</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*2,slf.CallTest)</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*2,slf.AsyncCallTest)</div><div><span style="white-space:pre"> </span>slf.AfterFunc(time.Second*2,slf.GoTest)</div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestService7) CallTest(){</div><div><span style="white-space:pre"> </span>var input InputData</div><div><span style="white-space:pre"> </span>input.A = 300</div><div><span style="white-space:pre"> </span>input.B = 600</div><div><span style="white-space:pre"> </span>var output int</div><div></div><div><span style="white-space:pre"> </span>//同步调用其他服务的rpc,inputZ入的rpc,output出参?/div><div><span style="white-space:pre"> </span>err := slf.Call("TestService6.RPC_Sum",&input,&output)</div><div><span style="white-space:pre"> </span>if err != nil {</div><div><span style="white-space:pre"> </span>fmt.Printf("Call error :%+v\n",err)</div><div><span style="white-space:pre"> </span>}else{</div><div><span style="white-space:pre"> </span>fmt.Printf("Call output %d\n",output)</div><div><span style="white-space:pre"> </span>}</div><div>}</div><div></div><div></div><div>func (slf *TestService7) AsyncCallTest(){</div><div><span style="white-space:pre"> </span>var input InputData</div><div><span style="white-space:pre"> </span>input.A = 300</div><div><span style="white-space:pre"> </span>input.B = 600</div><div><span style="white-space:pre"> </span>/*slf.AsyncCallNode(1,"TestService6.RPC_Sum",&input,func(output *int,err error){</div><div><span style="white-space:pre"> </span>})*/</div><div><span style="white-space:pre"> </span>//异步调用Q在数据q回Ӟ会回调传入函?/div><div><span style="white-space:pre"> </span>//注意函数的第一个参C定是RPC_Sum函数的第二个参数Qerr error为RPC_Sumq回?/div><div><span style="white-space:pre"> </span>slf.AsyncCall("TestService6.RPC_Sum",&input,func(output *int,err error){</div><div><span style="white-space:pre"> </span>if err != nil {</div><div><span style="white-space:pre"> </span>fmt.Printf("AsyncCall error :%+v\n",err)</div><div><span style="white-space:pre"> </span>}else{</div><div><span style="white-space:pre"> </span>fmt.Printf("AsyncCall output %d\n",*output)</div><div><span style="white-space:pre"> </span>}</div><div><span style="white-space:pre"> </span>})</div><div>}</div><div></div><div>func (slf *TestService7) GoTest(){</div><div><span style="white-space:pre"> </span>var input InputData</div><div><span style="white-space:pre"> </span>input.A = 300</div><div><span style="white-space:pre"> </span>input.B = 600</div><div></div><div><span style="white-space:pre"> </span>//在某些应用场景下不需要数据返回可以用GoQ它是不d?只需要填入输入参?/div><div><span style="white-space:pre"> </span>err := slf.Go("TestService6.RPC_Sum",&input)</div><div><span style="white-space:pre"> </span>if err != nil {</div><div><span style="white-space:pre"> </span>fmt.Printf("Go error :%+v\n",err)</div><div><span style="white-space:pre"> </span>}</div><div></div><div><span style="white-space:pre"> </span>//以下是广播方式,如果在同一个子|中有多个同名的服务名,CastGo会q播l所有的node</div><div><span style="white-space:pre"> </span>//slf.CastGo("TestService6.RPC_Sum",&input)</div><div>}</div><div></div><div>```</div><div>您可以把TestService6配置到其他的Node中,比如NodeId?中。只要在一个子|,origin引擎可以无差别调用。开发者只需要关注Service关系。同样它也是您服务器架构设计的核心需要思考的部分?/div><div></div><div></div><div>W六章:HttpService使用</div><div>---------------</div><div>HttpService是origin引擎中系l实现的http服务Qhttp接口中常用的GET,POST以及url路由处理?/div><div></div><div>simple_http/TestHttpService.go文g如下Q?/div><div>```</div><div>package simple_http</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"fmt"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/sysservice"</div><div><span style="white-space:pre"> </span>"net/http"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&sysservice.HttpService{})</div><div><span style="white-space:pre"> </span>node.Setup(&TestHttpService{})</div><div>}</div><div></div><div>//新徏自定义服务TestService1</div><div>type TestHttpService struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div>}</div><div></div><div>func (slf *TestHttpService) OnInit() error {</div><div><span style="white-space:pre"> </span>//获取pȝhttpservice服务</div><div><span style="white-space:pre"> </span>httpervice := node.GetService("HttpService").(*sysservice.HttpService)</div><div></div><div><span style="white-space:pre"> </span>//新徏q设|\由对?/div><div><span style="white-space:pre"> </span>httpRouter := sysservice.NewHttpHttpRouter()</div><div><span style="white-space:pre"> </span>httpervice.SetHttpRouter(httpRouter,slf.GetEventHandler())</div><div></div><div><span style="white-space:pre"> </span>//GETҎQ请求url:http://127.0.0.1:9402/get/query?nickname=boyce</div><div><span style="white-space:pre"> </span>//qheader中新增key为uid,value?000的头,则用postman试q回l果为:</div><div><span style="white-space:pre"> </span>//head uid:1000, nickname:boyce</div><div><span style="white-space:pre"> </span>httpRouter.GET("/get/query", slf.HttpGet)</div><div></div><div><span style="white-space:pre"> </span>//POSTҎ hurl:http://127.0.0.1:9402/post/query</div><div><span style="white-space:pre"> </span>//q回l果为:{"msg":"hello world"}</div><div><span style="white-space:pre"> </span>httpRouter.POST("/post/query", slf.HttpPost)</div><div></div><div><span style="white-space:pre"> </span>//GET方式获取目录下的资源Qhttp://127.0.0.1:port/img/head/a.jpg</div><div><span style="white-space:pre"> </span>httpRouter.SetServeFile(sysservice.METHOD_GET,"/img/head/","d:/img")</div><div></div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div>func (slf *TestHttpService) HttpGet(session *sysservice.HttpSession){</div><div><span style="white-space:pre"> </span>//从头中获取key为uid对应的?/div><div><span style="white-space:pre"> </span>uid := session.GetHeader("uid")</div><div><span style="white-space:pre"> </span>//从url参数中获取key为nickname对应的?/div><div><span style="white-space:pre"> </span>nickname,_ := session.Query("nickname")</div><div><span style="white-space:pre"> </span>//向body部分写入数据</div><div><span style="white-space:pre"> </span>session.Write([]byte(fmt.Sprintf("head uid:%s, nickname:%s",uid,nickname)))</div><div><span style="white-space:pre"> </span>//写入http状?/div><div><span style="white-space:pre"> </span>session.WriteStatusCode(http.StatusOK)</div><div><span style="white-space:pre"> </span>//完成q回</div><div><span style="white-space:pre"> </span>session.Done()</div><div>}</div><div></div><div>type HttpRespone struct {</div><div><span style="white-space:pre"> </span>Msg string `json:"msg"`</div><div>}</div><div></div><div>func (slf *TestHttpService) HttpPost(session *sysservice.HttpSession){</div><div><span style="white-space:pre"> </span>//也可以采用直接返回数据对象方式,如下Q?/div><div><span style="white-space:pre"> </span>session.WriteJsonDone(http.StatusOK,&HttpRespone{Msg: "hello world"})</div><div>}</div><div></div><div>```</div><div>注意Q要在main.go中加入import _ "orginserver/simple_service"Qƈ且在config/cluster/subnet/cluster.json中的ServiceList加入服务?/div><div></div><div></div><div></div><div>W七章:TcpService服务使用</div><div>---------------</div><div>TcpService是origin引擎中系l实现的Tcp服务Q可以支持自定义消息格式处理器。只要重新实现network.Processor接口。目前内|已l实现最常用的protobuf处理器?/div><div></div><div>simple_tcp/TestTcpService.go文g如下Q?/div><div>```</div><div>package simple_tcp</div><div></div><div>import (</div><div><span style="white-space:pre"> </span>"fmt"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/network/processor"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/node"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/service"</div><div><span style="white-space:pre"> </span>"github.com/duanhf2012/origin/sysservice"</div><div><span style="white-space:pre"> </span>"github.com/golang/protobuf/proto"</div><div><span style="white-space:pre"> </span>"orginserver/simple_tcp/msgpb"</div><div>)</div><div></div><div>func init(){</div><div><span style="white-space:pre"> </span>node.Setup(&sysservice.TcpService{})</div><div><span style="white-space:pre"> </span>node.Setup(&TestTcpService{})</div><div>}</div><div></div><div>//新徏自定义服务TestService1</div><div>type TestTcpService struct {</div><div><span style="white-space:pre"> </span>service.Service</div><div><span style="white-space:pre"> </span>processor *processor.PBProcessor</div><div><span style="white-space:pre"> </span>tcpService *sysservice.TcpService</div><div>}</div><div></div><div>func (slf *TestTcpService) OnInit() error {</div><div><span style="white-space:pre"> </span>//获取安装好了的TcpService对象</div><div><span style="white-space:pre"> </span>slf.tcpService =  node.GetService("TcpService").(*sysservice.TcpService)</div><div></div><div><span style="white-space:pre"> </span>//新徏内置的protobuf处理器,您也可以自定义\由器Q比如jsonQ后l会补充</div><div><span style="white-space:pre"> </span>slf.processor = processor.NewPBProcessor()</div><div></div><div><span style="white-space:pre"> </span>//注册监听客户q接断开事g</div><div><span style="white-space:pre"> </span>slf.processor.RegisterDisConnected(slf.OnDisconnected)</div><div><span style="white-space:pre"> </span>//注册监听客户q接事g</div><div><span style="white-space:pre"> </span>slf.processor.RegisterConnected(slf.OnConnected)</div><div><span style="white-space:pre"> </span>//注册监听消息cdMsgType_MsgReqQƈ注册回调</div><div><span style="white-space:pre"> </span>slf.processor.Register(uint16(msgpb.MsgType_MsgReq),&msgpb.Req{},slf.OnRequest)</div><div><span style="white-space:pre"> </span>//protobuf消息处理器设|到TcpService服务?/div><div><span style="white-space:pre"> </span>slf.tcpService.SetProcessor(slf.processor,slf.GetEventHandler())</div><div></div><div><span style="white-space:pre"> </span>return nil</div><div>}</div><div></div><div></div><div>func (slf *TestTcpService) OnConnected(clientid uint64){</div><div><span style="white-space:pre"> </span>fmt.Printf("client id %d connected\n",clientid)</div><div>}</div><div></div><div></div><div>func (slf *TestTcpService) OnDisconnected(clientid uint64){</div><div><span style="white-space:pre"> </span>fmt.Printf("client id %d disconnected\n",clientid)</div><div>}</div><div></div><div>func (slf *TestTcpService) OnRequest (clientid uint64,msg proto.Message){</div><div><span style="white-space:pre"> </span>//解析客户端发q来的数?/div><div><span style="white-space:pre"> </span>pReq := msg.(*msgpb.Req)</div><div><span style="white-space:pre"> </span>//发送数据给客户?/div><div><span style="white-space:pre"> </span>err := slf.tcpService.SendMsg(clientid,&msgpb.Req{</div><div><span style="white-space:pre"> </span>Msg: proto.String(pReq.GetMsg()),</div><div><span style="white-space:pre"> </span>})</div><div><span style="white-space:pre"> </span>if err != nil {</div><div><span style="white-space:pre"> </span>fmt.Printf("send msg is fail %+v!",err)</div><div><span style="white-space:pre"> </span>}</div><div>}</div><div>```</div><div></div><div></div><div>W八章:其他pȝ模块介绍</div><div>---------------</div><div>* sysservice/wsservice.go:支持了WebSocket协议Q用方法与TcpServicecM</div><div>* sysmodule/DBModule.go:对mysql数据库操?/div><div>* sysmodule/RedisModule.go:对Redis数据q行操作</div><div>* sysmodule/HttpClientPoolModule.go:Http客户端请求封?/div><div>* log/log.go:日志的封装,可以使用它构建对象记录业务文件日?/div><div>* util:在该目录下,有常用的uuid,hash,md5,协程装{工具库</div><div>* https://github.com/duanhf2012/originservice: 其他扩展支持的服务可以在该工E上看到Q目前支持firebase推送的装?/div><div></div><div></div><div>**Ƣ迎加入origin服务器开发QQ交流?168306674Q有M疑问我都会及时解{?*</div><div></div><div>提交bug及特? https://github.com/duanhf2012/origin/issues</div><div></div><div></div><div></div><img src ="http://www.shnenglu.com/API/aggbug/217287.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/API/" target="_blank">C++技术中?/a> 2020-05-07 16:06 <a href="http://www.shnenglu.com/API/archive/2020/05/07/217287.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>golang游戏服务器引?/title><link>http://www.shnenglu.com/API/archive/2020/05/07/217286.html</link><dc:creator>C++技术中?/dc:creator><author>C++技术中?/author><pubDate>Thu, 07 May 2020 08:04:00 GMT</pubDate><guid>http://www.shnenglu.com/API/archive/2020/05/07/217286.html</guid><wfw:comment>http://www.shnenglu.com/API/comments/217286.html</wfw:comment><comments>http://www.shnenglu.com/API/archive/2020/05/07/217286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/API/comments/commentRss/217286.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/API/services/trackbacks/217286.html</trackback:ping><description><![CDATA[<span data-offset-key="51d80-0-0" style="color: #1a1a1a; font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 15px; white-space: pre-wrap; background-color: #ffffff;"><span data-text="true">现在go语言比较行的有leaf,gowold,origin。前两个比较基础Q实现集还需要进行二ơ的~码设计。origin不一P只需要通过配置方便快速的集群?/span></span>originM设计如go语言设计一PL可能的提供z和易用的模式,快速开发?能够Ҏ业务需求快速ƈ灉|的制定服务器架构?利用多核优势Q将不同的service配置C同的nodeQƈ能高效的协同工作?整个引擎抽象三大对象,node,service,module。通过l一的组合模型管理游戏中各功能模块的关系?nbsp;<br /><br /><br /><div>origin引擎三大对象关系</div><div>---------------</div><div>* Node:   可以认ؓ每一个Node代表着一个originq程</div><div>* Service:一个独立的服务可以认ؓ是一个大的功能模块,他是Node的子集,创徏完成q安装Node对象中。服务可以支持对外部RPC{功能?/div><div>* Module: q是origin最对象单元,强烈所有的业务模块都划分成各个的Modulel合Qorigin引擎监控所有服务与Moduleq行状态,例如可以监控它们的慢处理和死循环函数。Module可以建立树状关系。Service本n也是Module的类型?br /><br />更加详细的参照项目地址Q?a >https://github.com/duanhf2012/origin</a></div><img src ="http://www.shnenglu.com/API/aggbug/217286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/API/" target="_blank">C++技术中?/a> 2020-05-07 16:04 <a href="http://www.shnenglu.com/API/archive/2020/05/07/217286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SVN分支/合ƈ原理及最佛_??http://www.shnenglu.com/API/archive/2017/04/12/214834.htmlC++技术中?/dc:creator>C++技术中?/author>Wed, 12 Apr 2017 07:15:00 GMThttp://www.shnenglu.com/API/archive/2017/04/12/214834.htmlhttp://www.shnenglu.com/API/comments/214834.htmlhttp://www.shnenglu.com/API/archive/2017/04/12/214834.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/214834.htmlhttp://www.shnenglu.com/API/services/trackbacks/214834.html使用svn几年了,一直对分支和合q敬而远之,一来是因ؓ分支的管理不该我操心Q二来即使涉及到分支的管理,也不敢N然用合q功能,生怕合q出了问题对团队造成不良影响Q最主要的原因是Q自己对分支的目的和合ƈ的方法不甚了解,q才是硬伤?/p>


最q由于适配机型的需要(本h从事手机客户端的开发)Q需要经常接触分支和合ƈ两项工作Q突然发现这玩意整不明白很难开展工作,遂这两天着重研I了一下,有点收获Q怕以后忘了,故趁着余温在赶紧写下来,好记性不如烂W头嘛。下文的实践主要是参考了TortoiseSVN的帮助文档和Subversion的在U文档,Subversion的在U文档:http://svnbook.red-bean.com/en/1.5/svn-book.html


话说我公司现在的源代码管理挺qQsvn目录q没有采取标准的source/branches、source/trunkl构Q主U和分支攑־到处都是Qrelease版本也ƈ没有当成tag处理Q而是当成branch来管理,l常q要在release版本上改来改厅R。?/p>


先说说什么是branch。按照Subversion的说法,一个branch是某个development lineQ通常是主U也即trunkQ的一个拷贝,见下图:

branch存在的意义在于,在不q扰trunk的情况下Q和trunkq行开发,待开发结束后合ƈ回trunk中,在branch和trunk各自开发的q程中,他们都可以不断地提交自己的修改,从而得每ơ修改在repository中都有记录?/p>



设想以下场景Q如果你的项目需要开发一个新功能Q而该功能可能会修攚w目中的绝大多数文Ӟ而与此同Ӟ你的另一位同事正在进行bug fixQ如果你的新功能不在branch中开发而直接在trunk中开发,那么你极有可能媄响另一位同事的bug fixQ他/她在bug修复中可能会遇到各种各样的问题,因ؓ你的频繁提交代码引入了过多的不稳定因素。你可能会说Q那我在开发的q程中不提交不就行了Q等到我全部开发结束我再提交,是,你可以这么做Q那q要版本控制q什么呢Q也许等C最后提交代码的时候(也许一周,也许两周Q)Q你会发现有一大堆conflict{着你resolve。。?/p>


那么Q正的做法是什么?使用branchQ从trunk创徏branchQ然后在你的branch上开发,开发完成后再合q到trunk中?br />


关于branch先讲到这里,下面说说什么叫做合q。很好理解,当branch开发完成后Q包括必要的Q,branch中的修改同步到trunk中,q个q程有可能包括修Ҏ件、增加文件、删除文件等{?/p>


说到q里Q貌似本文差不多可以l束了,不就是分支和合ƈ么?只要再简单地说说如何建立分支和如何合q就可以收尾了,可能只需两个命oQ也可能只需鼠标点几下然后键盘敲两下卛_。其实事情远非这么简单,爱动脑筋的同学可能会问了Q将branch的改动merge到trunk的时候,和上文说的直接在trunk中全部开发完然后提交有何区别Q你最后还不是要处理一大堆conflictQ?/p>


q个问题问得非常好,其实q正是本文的重点Qbranch和trunk在ƈ行开发的q程中如何感知对方,branch如何才能在开发过E中不会和trunk走远Q导致最后无法合qӞ试想一下,如果在你开发branch的过E中Qtrunk中的某个cL件已l被删除了(q可能是另外一个家伙在另一个branch上开发了两周后才合ƈ到trunk的)Q而你竟然在这个类文g上做了大量修改,试问你到最后合q回trunk的时候该有多蛋疼Q解册一问题的唯一手段是,branch要不停地和trunk保持同步Q你要及时地知道trunk都做了什么修改,q些修改是否会媄响你正在开发的新功能,如果需要,你必d时调整branch的代码,使之能与trunk“兼容”?/p>


那么如何让branch和trunk保持同步Q合qӞ从trunk合ƈ到branchQ你没听错,是从trunk合ƈ到branch。关于TortoiseSVN的合qӞ有几炚w要注意:

  • TortoiseSVN的合q发生在本地Q也即你的working copy中,你无需q多担心会对repository中的代码造成影响
  • 不管是从trunk合ƈ到branchq是最l从branch合ƈ回trunkQ在每次合ƈ前最好先updateQ然后将本地的修改先全部commitQ保护好现场Q万一合ƈ不理想随旉可以revert
  • 合ƈ完成后看是否能正编译,然后试验证Q最后将合ƈ后的改动提交到repository



下面我将step by step地演C如何一ơ完整的branching和mergingQ包括创建分支、分支开发、分支和ȝ同步Q分支合q到ȝ的全q程Q甚臛_括如何在本地创徏一个测试用的repository?/p>


首先需要安装TortoiseSVNQ我安装的版本是QTortoiseSVN 1.6.15, Build 21041 - 32 Bit , 2011/03/23 18:00:27


1、本地Repository的创?/strong>

repository的创建很单,假设我要在D:\TortoiseSVN\TestRepository目录中创建repositoryQ只需右键TestRepository目录Q依ơ选择"TortoiseSVN" -> "Create repository here"便完成了repository的创建?/p>


2、Check out

假设要check out到D:\TortoiseSVN\TestSVNQ同样很单,在D:\TortoiseSVN目录下创建TestSVN目录Q然后在该目录上右键Q选择"SVN Check out..."Q在弹出的窗口中?URL of repository"中填?file:///D:/TortoiseSVN/TestRepository"Q其他默认即可,最后点击ok?br />


3、trunk创徏新项目MyProject

相当单就不赘qCQ只列出本次操作所作出的修改:



4、创建branch

?trunk/MyProject目录上右键,依次选择"TortoiseSVN" -> "Branch/tag..."Q在弹出H口?To URL"中填入分支的地址Q在q里目标revision选择HEAD revisionQ如下图所C,dlog后点击ok分支便徏立了。这个操作速度非常快,新徏的branch在repository中其实只是一个指向trunk某个revision的Yq接而已Qƈ没有真的复制文g?/p>


5、Check out分支

右键TestSVN目录选择"TortoiseSVN Update"卛_刚刚徏立的分支下蝲回本地。进?branches/MyProject目录下你会发现其文gl构?trunk/MyProject一模一栗?br />


6、branch提交一个新文g


7、trunk紧接着提交一个修?br />

8、branch再次提交一个修?br />

9、将trunk中的修改同步到branch


6-8演示的是branch和trunk在独立、ƈ行地开发。ؓ了防止在“错误”的道路上走远Q现在branch意识到是时候和trunk来一ơ同步了Q将trunk合ƈ到branchQ?/p>

首先Q在本地trunk中先update一下,有冲H的解决冲突Q保证trunk和repository已经完全同步Q然后在/branches/MyProject上右键,依次选择"TortoiseSVN" -> “Merge...”Q在弹出的窗口中选择W一?Merge a range of revision"Q这个类型的Merge已经介绍得很清楚Q适用于将某个分支或主U上提交的多个revision间的变化合ƈ到另外一个分支上?br />


点击next后,出现如下H口Q?br />
׃是要从trunk合ƈ到branchQ理所当然q里?URL to merge from"应该填trunk的\径,"Revision range to merge"很好理解Q就是你要将trunk的哪些revision所对应的变化合q到branch中,可以是某一q串的revisionQ比?-7Q?5-HEADQ也可以是某个单独的revision受由于在r4中,trunk修改了Person.Java中的talk()ҎQ所以这里的revision只需?卛_。点击next后出C图:

在这里只需保留默认讄卛_。在点击Merge按钮前你可以先Test merge一把,看成功与否,以及merge的详l信息。点击Merge按钮后trunk所做的修改同步到branch中?/p>



10、提交合q后的branch


xQbranch已经完全和trunk同步Qbranch和trunk的代码相处很融洽Q没有Q何冲H,如果branch已经开发结束,那是时候将branch合ƈ回trunk了,当然Q如果branchq要l箋开发,那你不断地重复6-10q几个步骤?/p>


11、将branch合ƈ回trunk

?trunk/MyProject上右键(注意是在ȝ的目录上右键Q,依次选择"TortoiseSVN" -> "Merge..."Q在弹出的窗口中QMerge type选择W二?Reintegrate a branch"Q这U类型的合ƈ适合在分支开发结束后所有的改动合ƈ回主Uѝ?/p>



点击next后出现如下窗口:

在这里,"From URL"选择/branches/MyProjectQ无需选择revisionPReintegrate会将branch上所有修改合q到trunk。后面的步骤和上文第9步中的一P不再啰嗦了。如无意外,branch成功合q到trunkQ你需要做的只是将合ƈ后的trunk赶紧commitQ?/p>


12、提交合q后的trunk

so easy...


13、删除branch

如果你认Z新加的功能已l开发完成了Q你可以删除你的分支



到这里,我已l给你演C完了整个过E,我一w的汗也下来了,我想|工了,不过最后我们还是看看所有的log信息吧,通过log能发现我们干的所有事情:

r1-r7正是我上文在q的事情Q从Message中你能发现我对trunk和branch都干了什么,另外Q在Log MessagesH口的左下角N了"Include merged revisions"你还能看到额外的Merge informationQ?br />

图中灰色的是和merge相关的logQ共发生了两ơmergeQ第一ơ是在r6Q在r6中,branch合ƈ了trunk在r4时提交的变化Q第二次是在r7Q在r7中,trunk合ƈ了branch从r2到r6的所有变化?br />




l于可以写写ȝ了:

  • branch主要用于新功能的开?/li>
  • 合ƈ发生在本地working copyQ只要你不提交就不会影响到repository
  • 合ƈ前一定要先update、commitQ保证不会out of dayQƈ本地的修改保存到repository
  • branch和trunkq行开发的q程中,要经常同步,trunk的修改合q到branchQ合q时选择"Merge a range of revision"
  • branch最后合q回trunkӞmerge type选择"Reintegrate a branch"


]]>
protobuf repeatedcd的?/title><link>http://www.shnenglu.com/API/archive/2014/12/09/209070.html</link><dc:creator>C++技术中?/dc:creator><author>C++技术中?/author><pubDate>Tue, 09 Dec 2014 11:14:00 GMT</pubDate><guid>http://www.shnenglu.com/API/archive/2014/12/09/209070.html</guid><wfw:comment>http://www.shnenglu.com/API/comments/209070.html</wfw:comment><comments>http://www.shnenglu.com/API/archive/2014/12/09/209070.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/API/comments/commentRss/209070.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/API/services/trackbacks/209070.html</trackback:ping><description><![CDATA[<p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">protobuf是Google开发的一个序列化框架Q类似XMLQJSONQ基于二q制Q比传统的XML表示同样一D内容要短小得多。通过protobufQ可以很L的调用相x法来完成业务数据的序列化与反序列化。protobuf repeatedcd相当于std的vectorQ可以用来存放N个相同类型的内容Q文章将单介lprotobuf repeated的用?/p><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;">首先定义一个protobufl构Q如下:<br /></p><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->message Person {<br />  required int32 age = 1;<br />  required <span style="color: #0000FF; ">string</span> name = 2;<br />}<br /><br />message Family {<br />  repeated Person person = 1;<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br />下面我们以例子简单说明如何用:<br /></p><div style="font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; background-color: #eeeeee;"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">int</span> main(<span style="color: #0000FF; ">int</span> argc, <span style="color: #0000FF; ">char</span>* argv[])<br />{<br /><br />    GOOGLE_PROTOBUF_VERIFY_VERSION;<br /><br />    Family family;<br />    Person* person;<br /><br />    <span style="color: #008000; ">//</span><span style="color: #008000; "> d一个家庭成员,John</span><span style="color: #008000; "><br /></span>    person = family.add_person();<br />    person->set_age(25);<br />    person->set_name("John");<br /><br />    <span style="color: #008000; ">//</span><span style="color: #008000; "> d一个家庭成员,Lucy</span><span style="color: #008000; "><br /></span>    person = family.add_person();<br />    person->set_age(23);<br />    person->set_name("Lucy");<br /><br />    <span style="color: #008000; ">//</span><span style="color: #008000; "> d一个家庭成员,Tony</span><span style="color: #008000; "><br /></span>    person = family.add_person();<br />    person->set_age(2);<br />    person->set_name("Tony");<br /><br />    <span style="color: #008000; ">//</span><span style="color: #008000; "> 昄所有家庭成?/span><span style="color: #008000; "><br /></span>    <span style="color: #0000FF; ">int</span> size = family.person_size();<br /><br />    cout << "q个家庭?nbsp;" << size << " 个成员,如下Q? << endl;<br /><br />    <span style="color: #0000FF; ">for</span>(<span style="color: #0000FF; ">int</span> i=0; i<size; i++)<br />    {<br />        Person psn = family.person(i);<br />        cout << i+1 << ". " << psn.name() << ", q龄 " << psn.age() << endl;<br />    }<br /><br />    getchar();<br />    <span style="color: #0000FF; ">return</span> 0;<br />}</div><p style="color: #333333; font-family: Arial; line-height: 26px; background-color: #ffffff;"><br /></p><img src ="http://www.shnenglu.com/API/aggbug/209070.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/API/" target="_blank">C++技术中?/a> 2014-12-09 19:14 <a href="http://www.shnenglu.com/API/archive/2014/12/09/209070.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>cocos2dx环境搭徏http://www.shnenglu.com/API/archive/2014/07/01/207481.htmlC++技术中?/dc:creator>C++技术中?/author>Tue, 01 Jul 2014 09:34:00 GMThttp://www.shnenglu.com/API/archive/2014/07/01/207481.htmlhttp://www.shnenglu.com/API/comments/207481.htmlhttp://www.shnenglu.com/API/archive/2014/07/01/207481.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/207481.htmlhttp://www.shnenglu.com/API/services/trackbacks/207481.html一Q?      前期准备
cocos2d-x2.2.1  
2013q?1?9日更?/div>
下蝲地址Qhttp://www.cocos2d-x.org/download
 
2.jdk
java环境是必ȝQ这个在官网上下?/div>
下蝲地址Qhttp://www.java.com/zh_CN/download/manual.jsp
3. Android开发环?/div>
q个是android交叉~译必须的IDE环境Q内含Eclipse
下蝲地址Qhttp://developer.android.com/sdk/index.html
 
4.Android NDK
android交叉~译Ӟ对C/C++代码的解释编译工?/div>
下蝲地址Qhttp://developer.android.com/tools/sdk/ndk/index.html
 
5.python
cocos2d-x2.0版本以后用python脚本来创建工E,所以需要python环境
下蝲地址Qhttp://www.python.org/download/
注意Q请下蝲python2.7.6  64位版本,不要?.3的版?/div>
 
 
6.cygwin
对cocos2d-x本地C/C++代码的解释编译工?/div>
下蝲地址Qhttp://cygwin.com/install.html
 
x我们所需要的软g都已l准备完毕,接下来可以开始正式搭建环境了!
二.       搭徏Android开发环?/div>
1.java环境
android环境的搭建少不了javaQ先把下载好的JDK选择默认路径安装好后Q然后用wmic命o向系l添加java的环境变量?/div>
win+Rq行cmdQ输入以下三个命令:
wmic ENVIRONMENT create name="JAVA_HOME",username="<system>",VariableValue="C:\Program Files\Java\jre7"
以上Z?/div>
wmic ENVIRONMENT create name="CLASSPATH",username="<system>",VariableValue=";%JAVA_HOME%\lib\;"
以上Z?/div>
wmic ENVIRONMENT where "name='path' and username='<system>'" set VariableValue="%path%;C:\Program Files\Java\jre7\bin"
以上Z?/div>
然后q入pȝ环境变量讄界面更新一下,重启cmdQ试一下输入javaQ只要不是出?#8220;java不是内部命o或外部命?#8221;之类的,pCZ讄成功了?/div>
2.Android环境
扑ֈ我们下蝲的adt-bundle-windows-x86_64-20131030.zipQ解压,路径可以自己配置Q还是注意英文\径,不加I格卛_?/div>
接着q行adt-bundle-windows-x86_64-20131030\eclipse下的eclipseQADT自带Eclipse~译环境Q,选择工程文g夹,q里可以随意配置
 
接着x说明,q入ȝ面。在ȝ面点击配|SDK
然后可以按照需求选择Android SDK的版本,q里我选择下蝲AndroidQAPI 8Q,然后选择安装
 
 
 
慢慢{待下蝲安装l束?/div>
接下来配|Android VDM
 
然后选择DeviceDefinitionsQ随侉K择一个创建,好像是现在的VDM不支持OpenGL的高版本Q所以我使会用BlueStacks模拟器来调试Q这里只是生成apk
 
三.       安装cygwinQ配|Android NDK
q行下蝲好的cygwin-setup-x86_64.exeQ看C列安装界?/div>
 
点击下一?/div>
 
l箋
 
 默认路径安装Q然后选择下蝲保存的\径,q个大家可以自己配置Q安装完毕后最好做个备份,免得再次需要安装时q要下蝲
 
默认选择Q下一?/div>
选择W一个网?/div>
q里注意了,一定要红框标出来的点M下,变成install
 
点击下一步,漫长的等待下载~~~~~~
l于安装完毕Q我们赶紧打开来试试吧
W一ơ点开cygwin目录会在c:\cygwin64\home文g下生成以pȝd账户为名字的文g?/div>
现在Q将我们下蝲下来的Android NDK也就是android-ndk-r9b-windows-x86_64.zip解压~至英文路径下,q个路径会在接下来写入到cygwin?bash_profile配置文g中,好了Q我的解压\径ؓQD:\ android-ndk-r9b
注意Q该路径不能存在I格Q全英文
大家在c:\cygwin\home文g下生成的以系l登录̎户ؓ名字的文件夹下找?bash_profile文gQ点d键,用EditPlus软g打开Q在l尾处输入回车,接着输入下列语句Q?/div>
NDK_ROOT="/cygdrive/d/android-ndk-r9d"
export NDK_ROOT
 
NDK_MODULE_PATH="/cygdrive/d/cocos2d-x-2.2.1:/cygdrive/d/cocos2d-x-2.2.1/cocos2dx/platform/third_party/android/prebuilt"
export NDK_MODULE_PATH
 
然后点击保存Q关闭。这里的cygwin是指本地盘Qd是d盘,后面是NDK路径Q大家按照自q文g路径填写Q注意windows路径?#8220;\”和cygwin?#8220;/”的区别。顺便提一句,目录一直要写到有ndk-build.cmd文g的文件夹?/div>
四.       安装pythonQ创qcocos2d-x工程
安装我们已经下蝲好的python-2.7.6.amd64Q选择默认路径?/div>
 
安装完毕Q我们接下来使用python命o创徏自己的cocos2d-x工程?/div>
首先需要设|python的系l环境,׃刚才是默认安装,所以python的安装\径ؓC:\Python27\Q大家可以手动在开?>计算机(在上面点右键Q?>属?>高pȝ讄->环境变量中设|path路径Q添加python的安装目录?/div>
好了Q赶紧试一下我们的配置是否正确吧。在cmd输入命oQ?/div>
python -?
然后balabala...出现一堆,q就说明我们的python配置好了?/div>
接下来用python创徏工程。进入cocos2d-x-2.2.1目录下的tools->project-creatorQ大家可以看到有一个create_project.py脚本Q如果有兴趣可以右键在IDE中打开来看看,从中可以截取到该脚本的用方?/div>
 
好了Q我们赶快将q个脚本使用h?/div>
先在cocos2d-x-2.2.1目录下徏一个projects文g夹,在project-creator目录下按住shift+鼠标右键Q选择在此处打开命oH口Q输入命令:
python create_project.py -project HelloWorld -package org.HelloWorld.game -language cpp
然后{待l果
 
大家可以看到Q我们的工程创徏完毕了,其中QHelloWorld是我们命令中输入的工E名Q也是在cocos2d-x-2.2.1->projects文g夹下创徏了我们的工程Q名字就是HelloWorldQ在HelloWorld文g夹下的proj.android文g夹就是我们之后需要编译的android目Q创建命令后面的org.HelloWorld.game是安卓APK的识别名Q大家可以按?#8220;xxx.xxx.xxx”的格式自己命名?/div>
q里我写了一个bat批处理,大家可以攑֜project-creator目录下,以后可以很方便的创徏工程?/div>
在project-creator目录下点右键创徏一个文本文档,打开Q将以下内容复制q去Q然后点保存Q更Ҏ件的后缀名ؓbat卛_
-----------------------------------------------------------------------------------------
@echo off
:label1
@cls
echo Ƣ迎使用Python创徏Cocos2d-x工程
set /p project=误入需要创建的工程?
set /p aID=误入需要创建的android版本包标识名:
echo 您输入的工程名ؓ%project%
echo 您输入的android版本包标识名?aID%
echo 认创徏工程?
CHOICE /C 123 /M "认h 1Q取消请?2Q或者退?3?
echo %errorlevel%
if %errorlevel%==1 goto label2
if %errorlevel%==2 goto label1
if %errorlevel%==3 goto label3
:label2
echo 正在创徏工程...
python create_project.py -project %project% -package %aID% -language cpp
:label3
pause
-----------------------------------------------------------------------------------------
五.       在Ecliopse下编译Android目
好了Q以上我们所有的环境都已搭徏完成Q在我们的目导入eclipse之前Q我们还需要将cocos2d-x-2.2.1\cocos2dx\platform\android\java\src下的org文gҎ贝至我们的项目中Q也是cocos2d-x-2.2.1\projects\HelloWorld\proj.android\src下,׃我们之前创徏目时定的android包名前面也是orgQ所以会有覆盖选项Q请选择合ƈ覆盖卛_
接着Q回到eclipse环境Q导入项?/div>
 
 
 
注意在选择路径时写到HelloWorld文g夹下卛_
导入工程后,在工EHelloWorld上点选右键,选择Properties
 
 
选择buildersQ点击New
 
选择program
 
然后在接下来的界面中?/div>
name栏输入:Native_Builder
Location栏输入:C:\cygwin\bin\bash.exe
Arguments栏输入:--login -c "cd  D:/cocos2d-x-2.2.1/projects/HelloWorld/proj.android && /cygdrive/d/android-ndk-r9b/ndk-build"
 
以上Z?/div>
 
选择OKQ选中Native_BuilderQƈ其调到最上面
 
然后选择C/C++ Build->Environment->Add
 
 
接下来在Name栏输入pathQ在Value栏输入C:\cygwin\bin
 
然后在Java Build Path里面选择Libraries栏,Android Dependencies以及Android Private Libraries两个library删掉
 
Q说明一下,以上我们是将cygwin的编译环境合q到了Eclipse里,Eclipse利用cygwinq调用cygwin的bash以及makeQ通过NDK来编译我们的AndroidE序Q所以每ơ导入新的工E都要将上述步骤重新配置一下,q点非常重要Q如果配|不正确Q会D很多莫名其妙的报错,最典型的错误就是提C找不到bash命o什么的~~~~Q?/div>
好了Q现在我们可以生成APK文g了,在主界面选中自己的工E,然后在命令条上选择Run->Run as->Android Application
 
 
在编译的q程中,会有各种~译错误的问题,q是我碰到的三个Q?/div>
please define NDK_ROOT
解决ҎQ?/div>
在工E的proj.android目录下的build_native.sh中加?/div>
export NDK_ROOT=/cygdrive/e/android-ndk-r9
Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml   
解决办法Q?/div>
在该工程的jni文g夹下Q创建(若不存在Q才创徏Q一个名为Application.mk的文Ӟ在其内写一句:
APP_PLATFORM := android-8
~译成功Q但是bin目录下没有生成apk文g
解决办法Q?/div>
在工E的proj.android目录下的build_native.sh中加?/div>
chmod 666 -R "$APP_ANDROID_ROOT"/assets
 
如果以上步骤都按照步骤设定的话,p够生成APK了,APK存放在proj.android->bin文g夹下
快将APK装在自己的真Zq行试吧!Q!Q!
以上~译环境配|结束了?/div>
 


]]>lua常用函数http://www.shnenglu.com/API/archive/2014/06/27/207436.htmlC++技术中?/dc:creator>C++技术中?/author>Fri, 27 Jun 2014 07:34:00 GMThttp://www.shnenglu.com/API/archive/2014/06/27/207436.htmlhttp://www.shnenglu.com/API/comments/207436.htmlhttp://www.shnenglu.com/API/archive/2014/06/27/207436.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/207436.htmlhttp://www.shnenglu.com/API/services/trackbacks/207436.htmllua_newtable
void lua_newtable (lua_State *L);

创徏一个空 table Qƈ之压入堆栈?它等价于 lua_createtable(L, 0, 0) ?/p>

 

lua_gettop

int lua_gettop (lua_State *L);

q回栈顶元素的烦引?因ؓ索引是从 1 开始编LQ?所以这个结果等于堆栈上的元素个敎ͼ因此q回 0 表示堆栈为空Q?/p>

 

luaL_newmetatable

int luaL_newmetatable (lua_State *L, const char *tname);

如果注册表中已经有Key为tname的数据则q回0. 否则创徏一个新表作为userdata的metatableQƈ在注册表中注册它然后q回1. 不过两种情况都会把注册表中tname相关的值压入堆栈?/span>

luaL_checkudata

void *luaL_checkudata (lua_State *L, int narg, const char *tname);

Checks whether the function argument narg is a userdata of the type tname (see luaL_newmetatable).

lua_pushstring

void lua_pushstring (lua_State *L, const char *s);

把指?nbsp;s 指向的以零结字符串压栈?Lua 对这个字W串做一ơ内存拷贝(或是复用一个拷贝)Q?因此 s 处的内存在函数返回后Q可以释放掉或是重用于其它用途?字符串中不能包含有零字符Q第一个碰到的零字W会认ؓ是字W串的结束?/p>

 

lua_pushlstring

void lua_pushlstring (lua_State *L, const char *s, size_t len);

把指?nbsp;s 指向的长度ؓ len 的字W串压栈?Lua 对这个字W串做一ơ内存拷贝(或是复用一个拷贝)Q?因此 s 处的内存在函数返回后Q可以释放掉或是重用于其它用途?字符串内可以保存有零字符?/p>

 

lua_pushvalue

void lua_pushvalue (lua_State *L, int index);

把堆栈上l定有效处烦引处的元素作一个拷贝压栈?/p>

 

lua_settable

void lua_settable (lua_State *L, int index);

作一个等价于 t[k] = v 的操作, q里 t 是一个给定有效烦?nbsp;index 处的| v 指栈的| ?nbsp;k 是栈之下的那个倹{?/p>

q个函数会把键和值都从堆栈中弹出?和在 Lua 中一Pq个函数可能触发 "newindex" 事g的元Ҏ Q参?nbsp;§2.8Q?/p>

                                                                                                                                                                                                                                                                      

lua_pushcfunction

void lua_pushcfunction (lua_State *L, lua_CFunction f);

一?C 函数压入堆栈?q个函数接收一?C 函数指针Qƈ一个类型ؓ function ?Lua ?压入堆栈。当q个栈定的D调用Ӟ触发对应的 C 函数?/p>

注册?Lua 中的M函数都必遵循正的协议来接收参数和q回?Q参?nbsp;lua_CFunctionQ?/p>

lua_pushcfunction 是作Z个宏定义出现的:

      #define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)

 

 

lua_setmetatable

int lua_setmetatable (lua_State *L, int index);

把一?table 弹出堆栈Qƈ其设ؓl定索引处的值的 metatable ?/p>

 

lua_pushcclosure

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

把一个新?C closure 压入堆栈?/p>

当创Z一?C 函数后,你可以给它关联一些|q样是在创Z?C closure Q参?nbsp;§3.4Q; 接下来无论函C时被调用Q这些值都可以被这个函数访问到?Z一些值关联到一?C 函数上, 首先q些值需要先被压入堆栈(如果有多个|W一个先压)?接下来调?nbsp;lua_pushcclosure 来创建出 closure q把q个 C 函数压到堆栈上?参数 n 告之函数有多个值需要关联到函数上?nbsp;lua_pushcclosure 也会把这些g栈上弹出?/p>

 

lua_newuserdata

void *lua_newuserdata (lua_State *L, size_t size);

q个函数分配分配一块指定大的内存块, 把内存块地址作ؓ一个完整的 userdata 压入堆栈Qƈq回q个地址?/p>

userdata 代表 Lua 中的 C 倹{?完整?userdata 代表一块内存?它是一个对象(像 table 那样的对象)Q?你必d建它Q它有着自己的元表,而且它在被回收时Q可以被监测到?一个完整的 userdata 只和它自q{(在等于的原生作用下)?/p>

?Lua 通过 gc 元方法回收一个完整的 userdata Ӟ Lua 调用q个元方法ƈ?userdata 标记为已l止?{到q个 userdata 再次被收集的时候,Lua 会释放掉相关的内存?/p>

 

lua_touserdata

void *lua_touserdata (lua_State *L, int index);

如果l定索引处的值是一个完整的 userdata Q函数返回内存块的地址?如果值是一?light userdata Q那么就q回它表C的指针?否则Q返?nbsp;NULL ?/span>

 

 

Lua调用C++c要点:

1.       为此cd立一个全局表,表名为类名tbClassQ?/p>

lua_newtable(L);

int methods = lua_gettop(L);

lua_pushstring(LT::className);

lua_pushvalue(Lmethods);

lua_settable(LLUA_GLOBALSINDEX);

 

 

2Q注册一个key为T::className的metatableQƈ制定其中的一些成员,用于之后生成的userdata?/p>

// q个表用于userdata(T的对?的metatable

          luaL_newmetatable(LT::className);

          int metatable = lua_gettop(L);

         // metatable["__index"] = tbClass

         lua_pushliteral(L"__index");

         lua_pushvalue(Lmethods);

         lua_settable(Lmetatable);

// metatable["__tostring"] = tostring_T

         lua_pushliteral(L"__tostring");

         lua_pushcfunction(Ltostring_T);

         lua_settable(Lmetatable);

     // metatable["__gc"] = gc_T

         lua_pushliteral(L"__gc");

         lua_pushcfunction(Lgc_T);

         lua_settable(Lmetatable);

 

 

 

3Q?nbsp;为此表指定成员,每个成员的key为类的成员函数名QValueZ个带有闭包的l一函数。比如tbClass[FunName] = thunkQ之后可以根据闭包得到具体是调用到哪个函数。闭包中有函数名和相应函数的l合l构(以lightuserdata的Ş式赋l闭?。这些类成员函数参数都必d括lua_StateQ因为它需要的参数都会在lua堆栈中?/p>

// 为tbClass填充成员函数

         for (RegType *l = T::methodsl->namel++)

         {

              /* edited by Snaily: shouldn't it be const RegType *l ... ? */

              lua_pushstring(Ll->name);

// ?函数?函数地址)pair以lightuserdata的Ş式作为C closure的upvalue入栈

              lua_pushlightuserdata(L, (void*)l);

// 把一个新的C closure 压入堆栈。ؓupvalue的个敎ͼq指定回调函数统一为thunk    lua_pushcclosure(Lthunk, 1);         

// tbClass[FunName] = Function

lua_settable(Lmethods);

         }

 

4Q创建C对象l脚本用b = Account.new(Account, 30); new是tbClass下的一个函?另外指定的,不会掉到thunkQ这一句会调用到C的一个函敎ͼ里面会生成一个C对象Q然后创Z个userdata 用于兌到这个新生成的C对象。最后ؓq个userdatal定上我们上面注册ؓT::classname的metatable。因为定制了metatable的__index成员Q所以当userdata找不到的成员会去调用__indexQ因Z前我们把__indexl定到tbClassQ所以也会调用到tbClass的相应成员?/p>

 

     // 创徏一个新的T对象Qƈ创徏一个基于userdataType的userdataQ其中保护了指向T对象的指?/span>

     static int new_T(lua_State *L)

     {

         lua_remove(L, 1);   // use classname:new(), instead of classname.new()

         T *obj = new T(L); // call constructor for T objects

         userdataType *ud =

              static_cast<userdataType*>(lua_newuserdata(Lsizeof(userdataType)));

         ud->pT = obj// store pointer to object in userdata

         luaL_getmetatable(LT::className); // lookup metatable in Lua registry

         lua_setmetatable(L, -2);

         return 1; // userdata containing pointer to T object

     }

 

5Q?nbsp;当脚本中指定函数被调用的时候,比如b:deposit(50.30)的时候,b是userdataQ它的metatable的__index和tbClassl定(?)Q所以会调用到tbClass的相应成员,是之前兌的thunkQ这个时候L的堆栈里面有q个函数的两个参敎ͼ一个是b本nQ一个是50.30。b是userdataQ可以根据它取出对象的指针。见W?步。另外函数被调用的时候,它相关的upvalue也可以取得到Q见步骤3。有了对象指针和相应的函敎ͼ调用也不为难了,C参数50.30是保存在堆栈中传l类的成员函数来取得?/p>

// 所有成员函数都会调用到q里Q然后根据upvalue来执行具体的成员函数

     static int thunk(lua_State *L)

     {

         // stack has userdata, followed by method args

         T *obj = check(L, 1); // the object pointer from the table at index 0.

         lua_remove(L, 1); // remove self so member function args start at index 1

         // get member function from upvalue

         RegType *l = static_cast<RegType*>(lua_touserdata(Llua_upvalueindex(1)));

         return (obj->*(l->mfunc))(L); // call member function

     }

     // Ҏ指定位置narg获得对象指针,q个userdata是在new_T的时候创建的

     static T *check(lua_State *Lint narg)

     {

         void *pUserData = luaL_checkudata(LnargT::className);   

         userdataType *ud = static_cast<userdataType*>(pUserData);    // q个是函数的upvalue

         if(!ud)

              luaL_typerror(LnargT::className);

         return ud->pT;

     }

 



]]>
lua5.1->lua5.0http://www.shnenglu.com/API/archive/2014/06/25/207409.htmlC++技术中?/dc:creator>C++技术中?/author>Wed, 25 Jun 2014 08:32:00 GMThttp://www.shnenglu.com/API/archive/2014/06/25/207409.htmlhttp://www.shnenglu.com/API/comments/207409.htmlhttp://www.shnenglu.com/API/archive/2014/06/25/207409.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/207409.htmlhttp://www.shnenglu.com/API/services/trackbacks/207409.html关键字:
  and break do else elseif end false for function if in local nil not or repeat return then true until while
使用变量不需要声明,L全局变量Q除非加"local"。local的作用域是在最里层的end和其配对的关键字之间。全局变量的作用域是整个程序。大写相关。定义一个变量的Ҏ是赋?Q?操作。变量类型,可以用type()函数来检查:
  Nil  I|所有没有用过的变量都是nil。nil既是值又是类型。变量清除直接给变量赋以nil倹{?br />  Boolean  布尔值true ?false。只有false和nil才被计算为falseQ而所有Q何其它类型的|都是true。比?Q空串等{,都是true?br />  Number  数|相当于C语言的double实数如:4 0.4 4.57e-3 0.3e12 5e+20
  Userdata  可以是宿ȝL数据cdQ常用的有Struct和指针?br />  Thread U程cdQ在Lua中没有真正的U程Q将一个函数分成几部䆾q行?br />  String  字符Ԍ可以包含'/0'字符Q可以定义很长的字符丌Ӏ用双引h单引号引用单行,"[["?]]"引用多行字符丌Ӏ新版支?[==["?]==]"多层标记Q?号个Cؓ层数。严格按层数匚w。支持一些{义字W:
/a?b退?f换页/n换行/r回R/t制表W?v垂直制表//反斜?"双引?'单引?[左中括号/]右中括号
  Table  关系表类型,功能强大。可以用除了nilLcd的值来作数l的索引和内宏V?br />  Table的定义:T1 = {}  T1[1]=10  T1["John"]={Age=27, Gender="Male"}
    q一句相当于T1["John"]["Gender"]="Male"
    索引是字W串时可以简写成QT1.John.Gender="Male"或T1.John={Age=27, Gender="Male"}
    W一Q所有元素之_L用逗号"Q?隔开Q?br />    W二Q所有烦引值都需要用"["?]"括v来;如果是字W串Q还可以L引号和中括号Q?br />    W三Q如果不写烦引,则烦引就会被认ؓ是数字,q按序自动?往后编Q?br />    T1=
    {
      10,  -- 相当?[1] = 10
      [100] = 40,
      John=  -- 如果你原意,你还可以写成Q["John"] =
      {
        Age=27,   -- 如果你原意,你还可以写成Q["Age"] =27
        Gender=Male   -- 如果你原意,你还可以写成Q["Gender"] ="Male"
      },
      20  -- 相当?[2] = 20
    }
  Function  函数也是一U类型,也就是说所有的函数本n是一个变量?br />函数的定义:function add(a,b) return a+b end 相当于add = function (a,b) return a+b end
如果函数只有一个参敎ͼ可以省略括号?br />return语言一定要写在end之前。在中间放上returnQ写成:do return end?br />函数可以接受可变参数个数Q用"..."来定义function sum (a,b,...)
?果想取得...所代表的参敎ͼ5.0版本可以在函C讉Karg局部变量(表类型)得到。如 sum(1,2,3,4)则,a = 1, b = 2, arg = {3, 4}Q在5.1版本多了一?..变量Q实际就是参数列表)Q区别只在于arg?..共同存在的情况,...会arg变nil?br />可以同时q回多个l果Q比如:function s() return 1,2,3,4 end
    a,b,c,d = s()  -- 此时Qa = 1, b = 2, c = 3, d = 4
使用面向对象~程Q?br />    t = { Age = 27, add = function(self, n) self.Age = self.Age+n end }
    print(t.Age)  -- 27
    t.add(t, 10) 可以写成Qt:add(10)
    print(t.Age)  -- 37

单行注释"--"。只?-后面W一个字W不是多行字W串引用W[[Q即为多行注释?/div>
语句之间可以用分?Q?隔开Q也可以用空白隔开?/div>
条g控制Qif 条g then … elseif 条g then … else … end
While循环Qwhile 条g do … end
Repeat循环Qrepeat … until 条g
For循环Qfor 变量 = 初|l点|步进 do … end
可以省略步进|q时候,for循环会?作ؓ步进倹{?/div>
For循环Qfor 变量1Q变?Q?#8230; Q变量N in表或枚D函数 do … end
语句块用do ?end 括v来的。可以在函数中和语句块中定局部变量?/div>
赋D句可以同时给多个变量赋倹{例如:a,b,c,d=1,2,3,4甚至是:a,b=b,a 方便的交换变量功?/div>
默认变量L全局的。定义局部变量,则在W一ơ赋值的时候用local说明。比如:
  local a,b,c = 1,2,3  -- a,b,c都是局部变?/div>
数D支?+, -, *, /,^,#,%。^表示指数乘方。比?^3 l果??.1版加?长度q算W。字W串的长度单位ؓ字节Q表的长度ؓnil前的整数索引个数Q也是数组的个敎ͼ如果有名为n的烦引,它的值就是长度?.1版引q?模运?/div>
?.."q接两个字符丌Ӏ如Q?This a " .. "string." -- {于 "this a string"
比较q算< > <= >= == ~=分别表示 于Q大于,不大于,不小于,相等Q不相等。Lq回true或false。对于TableQFunction和Userdatacd的数据,只有 == ?~=可以用。相{表CZ个变量引用的是同一个数据。比如: a={1,2}    b=a    print(a==b, a~=b)  -- true, false
    a={1,2}    b={1,2}    print(a==b, a~=b)  -- false, true
逻辑q算and, or, not只有false和nil才计ؓfalseQ其它Q何数据都计算为trueQ?也是trueQ?br />    and ?or的运结果不是true和falseQ而是和它的两个操作数相关?br />    a and bQ如果a为falseQ则q回aQ否则返回b
    a or bQ如?a 为trueQ则q回aQ否则返回b
q算W优先Q从高到低顺序如下:
    ^
    not - Q一元运)#
     * / %
     + -
     ..Q字W串q接Q?br />     < > <= >= ~= ==
     and
     or
     =
常用标准库函?
print (···)把所有参数打印出来,利用tostring (e)转换非字W。奇怪的是nil不能?.操作?br />table.insert (table, [pos,] value)在pos位置插入一个|默认是末?br />table.remove (table [, pos])在pos位置删除一个|默认是末?br />table.concat (table [, sep [, i [, j]]])用sep来连接数l里从i到j字符串或数字q返回一个长字符Ԍ默认用空串从1到末。如果j大于iQ返回空丌Ӏ?br />table.maxn (table)q回最大正数烦引或0?br />table.sort (table [, comp])Ҏl排序,排序函数默认?lt;?br />string.byte (s [, i [, j]])q回s串从i到j的数倹{旧版只支持2个参?br />string.char (···)和byte函数功能相反Q返?或多个数字对应的字符丌Ӏ?br />string.find (s, pattern [, init [, plain]])从s串中从init位置开始找到第一个匹配模式的子串位置Qƈq回L和终炏Vplain如果为trueQ忽略模式。如果用了捕获Q则增加q回捕获的部分?br />string.gmatch (s, pattern)q是一个P代函敎ͼ每次q回一个匹配的丌Ӏ旧版叫gfind。如果用了捕获Q则q回捕获的部分?br />string.gsub (s, pattern, repl [, n])用rep1替换。n限制替换个数?1-9表示被捕L倹{如果第3个参数是个函数ƈq回假,替换字符保持原配而不是旧版的IZ?br />string.sub (s, i [, j])q回s从位|i到j的子丌Ӏ负DCZ末尾往前数的位|。默认从1到末?br />string.match (s, pattern [, init])从init匚w或捕获D回。旧版没有这个函数?br />string.format (formatstring, ···)格式化输出?q可以输出安全字符丌Ӏ?br />string.rep (s, n)把s复制n?br />string.reverse (s)把s倒{。旧版没有这个函数?br />string.len (s)计算字符串长度?br />string.lower (s)写化。string.upper (s)大写化?br />io.read (···)"*n"M个数字,支持各种格式Q?*a"L个文Ӟ"*l":M行,默认Q?n"读n个字W?br />io.write (···)写字W或者数?br />io.lines ([filename])q代q回文g中的一行?br />pairs (t)q代q回表中的键值对
ipairs (t)q代q回数组中的索引和?br />module (name [, ···])创徏一个模块。require (modname)加蝲一个模?/div>
模式表:
.L字符%w字母和数?a字母%d数字%p标点字符%sI白W?大写字母表示相应集合的补?br />%u大写字母%l写字母%x十六q制数字%z代表0的字W?c控制字符
%是{义标?[]集合 ^补集
()表示捕获 %1-9是捕获?%bxy是以xy为标识的对称l构
?匚w前一字符0ơ或1?+匚w前一字符1ơ或多次
*最长匹配前一字符0ơ或多次 -最短匹配前一字符0ơ或多次
以^开头的模式只匹配目标串的开始部分,怼的,?l尾的模式只匚w目标串的l尾部分?/div>
c调用lua函数一般的q程?
1. load一个lua的文Ӟ形成一个闭包ƈ执行?br />2. 在栈中压入函数的名称
3. 依次在栈中压入函数的实参
4. 使用lua_pcall调用lua函数。 形式? lua_pcall(L, 参数个数,l果个数, 错误处理函数在栈中的索引)
    此时此函数相关的栈已l被清空。执行lua完毕后,如果成功Q结果依ơ将压入栈中Q 如果不成功,错误信息?压入栈中
5. 从栈中读取返回结果或者错误信息?/div>
lua调用c函数(写成库的例子)
lua调用库在windows下是dll文gQ在unix/linux下面是so文g
vs的过E如下:
1. 新徏一个dll的工E?br />2. 定义一个def文gQ定义dll的导出,mylib.def定义如下:
LIBRARY  mylib.dll
DESCRIPTION "first dll for lua"
EXPORTS
luaopen_mylib
3. ~写库,新徏一个cpp文g.
4. 定义库函敎ͼq里以pil的lsin函数Q输Z入参数的sin()?br />5. 定义luaL_reg数组Q这个是注册一pd公开llua调用的函数数l? 数组最后一个元素必L {NULL, NULL} 的luaL_regl构用来做结束标?
6. 用luaL_openlib声明d?/div>
5.1版本?.0版本的区别:
新模块系l,增量垃圾攉Qvarargs新机Ӟ多行字符串或引用的新语法Q??新操作符Q?metatable支持所有类型,使用luaconf.h来配|lua暂时避免版本冲突Q完善的reentrant parser。PilW二版包括了5.1的新内容Q增加了C子,Ҏ模块pȝQ多状态和垃圾攉的详l阐q?/div>
语法Q?br />函数传递可变参数用...来代替局部arg表。不使用...Ӟarg用法和旧版本一P但?..后(无论先后Q,局部arg都会变成nil?br />在repeat.until里,局部变量的生命周期覆盖到until条g后面Q?br />多行字符串或引用的新语法使用多层匚w代替以前的嵌套;
#?新操作符?/div>
库函敎ͼ
string.gfind改ؓstring.gmatchQ?br />如果调用string.gsub的第3个参数是个函敎ͼ如果函数q回假,替换字符保持原配而不是旧版的IZQ?br />table.setn废弃Qtable.getn改ؓ使用#Q?br />loadlib改ؓpackage.loadlibQ?br />math.mod改ؓmath.fmodQ?br />table.foreach和table.foreachi作废。可用for循环pairs或ipairs代替Q?br />require从package.path而不是LUA_PATH得到path|
collectgarbage (opt [, arg])参数从[limit]改ؓ更多选择Qgcinfo废弃改ؓcollectgarbage("count")Q?br />string.byte (s [, i [, j]])q回s串从i到j的数倹{旧版只支持2个参?br />string.match (s, pattern [, init])从init匚w或捕获D回。旧版没有这个函数?br />string.reverse (s)把s倒{。旧版没有这个函数?br />module (name [, ···])创徏一个模块。旧版没有这个函数?/div>
C APIQ?br />5.1版本增加了以luaL_开头的辅助库Auxiliary LibraryQ?br />luaL_getn改ؓlua_objlenQluaL_setn废弃Q?br />luaL_openlib改ؓluaL_registerQ?br />luaL_checkudata改ؓ抛出异常而不是返回NULL?br />luaopen_* functions不能直接调用Q改为像调用其它普通c函数一Lq程Q?br />lua_open改ؓlua_newstateQ可以设|内存分配方法。luaL_newstate默认使用realloc分配ҎQ?br />5.0的调用方法:
 lua_State *L = lua_open();
 luaopen_base(L);
 luaopen_string(L);
 luaopen_math(L);
5.1的调用方法:
 lua_State *L = luaL_newstate();
 lua_cpcall(L, luaopen_base, 0);
 lua_cpcall(L, luaopen_io, 0);
 lua_cpcall(L, luaopen_math, 0);
 lua_cpcall(L, luaopen_string, 0);
lua_pushcfunction(L, luaopen_*);lua_call();{h于lua_cpcall(L, luaopen_*, 0);
参考资料:
参考手册:http://www.lua.org/manual/5.x/
lua 5.1 win32解析器:http://luaforge.net/frs/download.php/2218/lua5_1_2_Win32_bin.zip
lua 5.1 VC++6.0 库:http://luaforge.net/frs/download.php/2241/lua5_1_2_Win32_vc6_lib.zip
luasocket 参考手册:http://www.cs.princeton.edu/~diego/professional/luasocket/reference.html
luasocket win32扩展包luasocket-2.0.1-lua5.1-win32下蝲Q?a style="color: #336699; text-decoration: none;">http://luaforge.net/frs/download.php/1618/luasocket-2.0.1-lua5.1-win32.zip
tolua++ 参考手册:http://www.codenix.com/~tolua/tolua++.html
tolua++ 1.0.92 源代码下载:http://www.codenix.com/~tolua/tolua++-1.0.92.tar.bz2
 
其他l验Q?br />lua的扩展库luasocket, luasql, luacom, kepler...
E序可以存成cpp也可以存成c, 如果?c为扩展名׃需要加extern "C"
c和lua交互的时候,栈的~号是从1-nQ也可以取负|-1表示末尾
讄环境变量LUA_PATH="E:/LuaEdit/myproject/?.lua"Q然后用require "lua?文g?。然后就可以直接使用lua文g里的函数而不需要dofile(路径)了。在windows下的路径如果?必须写成//Q或??/div>
lua5.1win32的解析器下蝲来后可以直接使用。luasocketwin32扩展包下载后Q需要正设|LUA_PATH=< LDIR>/?.lua;?.lua和LUA_CPATH=<CDIR>/?.dll;?.dll。然后运行lua解析器, require相应的socket包就可以了?/div>
在VC++6下编译带lua?dll文g的时候,在工E设|里必须指明LIBC.lib Libcmtd.lib的加载顺序。选择VC菜单Project->Settings->Link->Catagory然后?Object/library  Modules的Edit栏中填入LIBC.lib Libcmtd.lib。否则会出现Q?br />Linking...
LIBC.lib(crt0dat.obj) : error LNK2005: __cinit already defined in LIBCMTD.lib(crt0dat.obj)
 
新版本下表P带需要加pairs(t)Q旧版本以下代码l果是正的Q?br />Lua 5.1.2  Copyright (C) 1994-2007 Lua.org, PUC-Rio
> function print_contents(t)
>> for k,v in t do
>> print(k .. "=" .. v)
>> end
>> end
> print_contents{x=10, y=20}
stdin:2: attempt to call a table value
stack traceback:
        stdin:2: in function 'print_contents'
        stdin:1: in main chunk
        [C]: ?
 
新版本中?..和arg不能同时出现Q无论先后,...的出现都会arg为nilQ?br />print(#arg)
function test(...)
--print(...)
print(type(arg),#arg)
--print(...)
end
test(1,2,3,4)
print(#arg)
q行l果Q?br />E:/lua5_1_2_Win32_bin>lua5.1 e....lua 1 2 3
3
table   4
3
l果说明arg在新版本中还是可以用的Q但?..冲突Q跟全局表arg不冲H。但本地arg会覆盖全局的argQ如果两者都要调用该如何处理Q?..后,~译器仍然把函数里的arg看成是局部变量。因此变通的Ҏ是:
print(#arg)
t=arg
function test(...)
print(...)
arg=t
print(type(arg),#arg)
--print(...)
end
test(1,2,3,4)
print(#arg)
q和旧版本是一L。看来引?..的用意不是ؓ了区分全局和局部的arg。那I竟是ؓ了什么呢Q?
 
lua安装Q?br />Windows:  
把etc目录下的luavs.bat 拷到lua的解压根目录下直接运? 生成?h .dll .lib .exe文g都在src下?br />Linux:
$make linux && make install 标准的linux安装

在Windows XP SP2下用Visual C++ 6. ~译lua的过E分?步:
1Q徏立静态库工程Q编译库文g
     Lua库由标准库和核心库组成,我用的是5.1版本Q所有代码都攑֜src目录中。把src目录中除lua.c,luac.c文g外所有的*.c文gd到项目中Q设|一下输\径,F7~译可以了?br />2,建立Win32控制台工E?~译lua.exe Lua解释?br />   把lua.cd到工E中Qlink选项中包含进刚才~译好的lib文gQF7~译
3.再徏立Win32控制台工E, ~译luac.exe  Lua~译?br />   同上步一P~译成功后生成luac.exeQ?最好把q两个文件放在新建的bin文g下,在添加进pȝ的环境变量?nbsp;
 
tolua++在cygwin下不用SCons~译Q?br />详见http://lua-users.org/wiki/CompilingToluappWithoutScons
src/lib下:
gcc -shared -o tolua++.dll *.c /usr/local/lib/lua51.dll -I../../include -I/usr/local/include
gcc -c *.c  -I../../include -I/usr/local/include
ar rcsv libtolua++.a *.o
src/bin下:
gcc tolua.c toluabind.c -I../../include -I/usr/local/include -L /usr/local/lib -llua -L../lib/ -ltolua++
然后把所得到的文件复制到pȝ相应目录中?/div>
使用tolua?pkg生成.cpp的时候,在生成的.cpp最前面讄#define TOLUA_API extern "C" __declspec(dllexport)可以?dll文g导出时不改变文g名。貌D要加
#ifndef __cplusplus#define __cplusplus#endif
使用cygwin产生?dll文g不能被lua使用。用同一源文件在vc下生成的.dll文g是可以被lua用的?/div>
使用VC~译toluaӞ把除了tolua.c和xxx.defalt以外?c?h都包含进去,然后在tolua++.h里设|?#define TOLUA_API extern "C" __declspecQ不断得修改#include "tolua++.h"在各个文件中的位|,使得用dumpbin看到65个导出函Cؓ止。貌似VC6版本太低不能成功讄预编译处理选项Q因此这样麻?炏V编译成功后有.lib?dll文g供接下来?dll工程使用?/div>

extern "C" _declspec(dillexport)
extern "C" void DLL_EXPORT __stdcall
 
============
实际应用场景l习
============
一、利用Lua的Table实现cȝ多承:
    1、假讑֟cMؓB1、B2
    2、承的cMؓA
    3、用的时候类gQ?br />            Instance1 = A:new()
            Instance1:Method1(arg1, arg2)
    q个不难Q但是务必要掌握table的应?/div>
{案Q见OO.lua。在lua解析器下q行Qdofile "OO.lua"
 
二、利用lua的扩展包luasocket实现http的一个应用:
    1、构造http协议Q访?a style="color: #336699; text-decoration: none;">www.qq.comQ具体的讉K方式|上有例子?br />    2、在q回来的http包中Q取讯公司的客服电话L -- 需要用到lua的字W串查找和模式匹配函数?/div>
{案Q?br />下蝲lua5.1win32的解析器和luasocketwin32扩展包,正确讄LUA_PATH=< LDIR>/?.lua;?.lua和LUA_CPATH=<CDIR>/?.dll;?.dllQ?lt;CDIR>指向 luasocket-2.0.1-lua5.1-win32/libQ?lt;LDIR>指向luasocket-2.0.1-lua5.1- win32/lua。luaE序见Phone.lua。在lua解析器下q行Qdofile "Phone.lua"
----------------------------
http = require("socket.http")
qqweb = http.request("http://www.qq.com")
tel=string.match(qqweb,"腾讯客服电话Q?%d+%-%d+)")
print("您要的电话号码是Q?..tel)
-------------------------------

三、在Windows下,利用C++实现一个基本的Socketcd来给Lua使用Q?br />    1、结合tolua++q行~译Q生成Lua可以调用的dll文gQ请参考网上的资料来熟悉tolua++的?br />    2、假设dll文g名ؓMySocket.dllQ类为CMySocketQ则调用的时候类gQ?br />        require("MySocket")
        Instance1 = CMySocket:new()
        Instance2 = CMySocket:new()
        Instance1:Listen(9701)
        Instance2:Connect("127.0.0.1",9701)
{案Q?br />windows下编译luaQ?br />把etc目录下的luavs.bat 拷到lua的解压根目录下直接运? 生成?h .dll .lib .exe文g都在src下?br />把相应的.h文g和lua51.lib文g拯到VC相应目录下。lua.exe和lua51.dll为lua解析器?br />在cygwin下编译安装方法:$make linux && make install
用cygwin~译安装tolua++Q且不用SCons~译Q?br />src/lib下:
动态链接文Ӟ
gcc -shared -o tolua++.dll *.c /usr/local/lib/lua51.dll -I../../include -I/usr/local/include
静态连接文Ӟ
gcc -c *.c  -I../../include -I/usr/local/include
ar rcsv libtolua++.a *.o
src/bin下:
执行文gQ改名ؓtolua++.exeQ?br />gcc tolua.c toluabind.c -I../../include -I/usr/local/include -L /usr/local/lib -llua -L../lib/ -ltolua++
然后把所得到的文件复制到pȝ相应目录中?/div>
Ҏmysocket.h设计mysocketcL式,写成.pkg文g?/div>
产生binding文gmypkg.cpp备用Q此时要用到mysocket.hQtolua++ -o mypkg.cpp mysocket.pkg
适当修改一下生成的mypkg.cpp文gQ以后导出?dll文g函数名不变?br />#define TOLUA_API extern "C" __declspec
用以下方法在cygwin下编译的.dll文g不能被lua使用Q加载包会失败?br />g++ -shared -o MySocket.dll *.cpp  /usr/local/lib/lua51.dll -I/usr/local/include -I.. -L /usr/local/lib -ltolua++
改用VC来编译。先~译tolua++?br />把src下除了tolua.c和toluabind_default.x以外?c?h都包 含进厅R工E设|里要包含LIBC.lib Libcmtd.lib tolua.lib lua5.1.libQinclude和lib路径也要包含lua的。然后设|?define TOLUA_API extern "C" __declspec~译成功后就有tolua.lib和tolua.dll文g供接下来?dll工程使用?/div>
把bingding文gmypkg.cpp和写好的mysocket.cppQmysocket.h一起在VC下编译生?dll文g。工E设 |里要包含LIBC.lib Libcmtd.lib tolua.lib lua51.libQinclude和lib路径也要包含lua或tolua的。前面两个文仉序一定不要写错,否则产生如下错误Q?br />Linking...
LIBC.lib(crt0dat.obj) : error LNK2005: __cinit already defined in LIBCMTD.lib(crt0dat.obj)
~译产生的MySocket.dll文g可以被lua调用了?br />q行一个lua解析器程序实例,执行Q?br />require("MySocket")
Instance1 = CMySocket:new()
Instance1:Listen(9701)
再运行另一个lua解析器程序实例,执行Q?br />require("MySocket")
Instance2 = CMySocket:new()
Instance2:Connect("127.0.0.1",9701)


]]>利用c++与swig+luahttp://www.shnenglu.com/API/archive/2014/04/24/206699.htmlC++技术中?/dc:creator>C++技术中?/author>Thu, 24 Apr 2014 08:12:00 GMThttp://www.shnenglu.com/API/archive/2014/04/24/206699.htmlhttp://www.shnenglu.com/API/comments/206699.htmlhttp://www.shnenglu.com/API/archive/2014/04/24/206699.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/206699.htmlhttp://www.shnenglu.com/API/services/trackbacks/206699.htmlswigwin-2.0.9.zipQ官|地址http://www.swig.org/ 载解压后Q目录下有swig.exeE序
2. 在VS中新建工ETestLua
3.dhello.h代码如下Q?br />
#ifndef HELLO_H__
#define HELLO_H__

int sum( int a, int b );
class Test
{
public:
    int a;
    int b;
    Test();
    void print();
};

#endif/*HELLO_H__*/

4.dhello.cpp代码如下Q?br />
#include "stdafx.h"
#include "hello.h"

int sum( int a, int b )
{
    return (a + b);
}
Test::Test()
{
    a = 10;
    b = 20;
}
void Test::print()
{
    printf( "%d %d\n", a, b );
}

5.~写modulehello.i文g,内容如下Q?br />
%module hello
%{
#include "hello.h"
%}
%include "hello.h"

6.使用以下命o生成文g
swig.exe -c++ -lua c:\modulehello.i
于是生成Q?span style="font-size: 14px;">modulehello_wrap.cxx文g

7.在工E包?br />
C:\Program Files (x86)\Lua\5.1\include
W加库目?span style="font-size: 14px;">"C:\Program Files (x86)\Lua\5.1\lib"
q且导入?/span>lua51.lib

8.在工E文件TestLua.cpp代码如下Q?br />
#include "stdafx.h"
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
};
#include "modulehello_wrap.cxx"
extern "C"
{
    extern int luaopen_hello(lua_State* L); // declare the wrapped module
};
int _tmain(int argc, _TCHAR* argv[])
{
    lua_State *L;
    L=lua_open();
    luaopen_base(L);    // load basic libs (eg. print)
    luaopen_hello(L);    // load the wrappered module
    if (luaL_loadfile(L,"./hello.lua")==0) // load and run the file
        lua_pcall(L,0,0,0);
    else
        printf("unable to load %s\n","hello.lua");
    lua_close(L);

    return 0;
}

9.~写lua脚本hello.lua如下Q?br />
print( "试脚本是否被调? );
print( "hello" );
print( "hello, tpf" );
print( "看到hello的字?表示脚本被调? );

print( "-----------------------------" );

print( "下面试函数" );
print( hello.sum( 1, 2 ) );
print( "看到数字表示函数正常被调? );

print( "-----------------------------" );

print( "下面试c调? );
a = hello.Test();

print( "-----------------------------" );
print( "成员变量>>>", a.a );
print( "成员变量>>>", a.b );

print( "下面试成员函数" );
a:print();
print( "看到数字表示成员函数被正常调? );

10.得出l果如下Q?br />
试脚本是否被调?/div>
hello
hello, tpf
看到hello的字?表示脚本被调?/div>
-----------------------------
下面试函数
3
看到数字表示函数正常被调?/div>
-----------------------------
下面试c调?/div>
-----------------------------
成员变量>>>     10
成员变量>>>     20
下面试成员函数
10 20
看到数字表示成员函数被正常调?/div>

]]>c++多线E调用pythonhttp://www.shnenglu.com/API/archive/2013/12/06/204618.htmlC++技术中?/dc:creator>C++技术中?/author>Fri, 06 Dec 2013 02:34:00 GMThttp://www.shnenglu.com/API/archive/2013/12/06/204618.htmlhttp://www.shnenglu.com/API/comments/204618.htmlhttp://www.shnenglu.com/API/archive/2013/12/06/204618.html#Feedback2http://www.shnenglu.com/API/comments/commentRss/204618.htmlhttp://www.shnenglu.com/API/services/trackbacks/204618.html阅读全文

]]>
c++调用python函数http://www.shnenglu.com/API/archive/2013/12/06/204616.htmlC++技术中?/dc:creator>C++技术中?/author>Fri, 06 Dec 2013 02:02:00 GMThttp://www.shnenglu.com/API/archive/2013/12/06/204616.htmlhttp://www.shnenglu.com/API/comments/204616.htmlhttp://www.shnenglu.com/API/archive/2013/12/06/204616.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/204616.htmlhttp://www.shnenglu.com/API/services/trackbacks/204616.html1.当取多个q回值时,如下Q?br />
def mix(a, b) :  
    r1 
= a + b  
    r2 
= a - b  
    
return (r1, r2) # (7,3)

c++代码如下Q?br />
#include "python.h"
int _tmain(int argc, _TCHAR* argv[])
{
string filename = "cal"; // cal.py
string methodname_mix = "mix"; // function name

Py_Initialize();

// load the module
PyObject * pyFileName = PyString_FromString(filename.c_str());
PyObject
* pyMod = PyImport_Import(pyFileName);

// load the function
PyObject * pyFunc_mix = PyObject_GetAttrString(pyMod, methodname_mix.c_str());

// test the function is callable
if (pyFunc_mix && PyCallable_Check(pyFunc_mix))
{
PyObject
* pyParams = PyTuple_New(2);
PyTuple_SetItem(pyParams,
0, Py_BuildValue("i", 5));
PyTuple_SetItem(pyParams,
1, Py_BuildValue("i", 2));

// ok, call the function
int r1 = 0, r2 = 0;
PyObject
* pyValue = PyObject_CallObject(pyFunc_mix, pyParams);
PyArg_ParseTuple(pyValue,
"i|i", &r1, &r2);
if (pyValue)
{
printf(
"%d,%d\n", r1, r2); //output is 7,3
}

}

 
Py_Finalize();

return 0;
}

2.如果q回一个值时Q?br />
import string

def AddMult(a, b):
c
= a + b
print c
return c


c++代码如下Q?nbsp;
PyObject* pModule =NULL;
PyObject
* pFunc = NULL;
PyObject
* pArgs = NULL;
PyObject
* pRet = NULL;

Py_Initialize();

PyRun_SimpleString(
"import sys");
PyRun_SimpleString(
"sys.path.append('./')");

pModule
= PyImport_ImportModule("httpsend");
pFunc
= PyObject_GetAttrString(pModule, "AddMult");

//pArgs = Py_BuildValue("s, s", "This is ", "a python code");

pArgs
= Py_BuildValue("ii", 12,34);

pRet
= PyObject_CallObject(pFunc,pArgs);
int pyResult=0,pyResult2 = 0;
char *str;
int argRet = PyArg_Parse(pRet,"i", &pyResult);
if (argRet)
{
printf(
"yes!\n");
}

else
{
//错误
printf("error!\n");
}


if(pModule)
Py_DECREF(pModule);
if(pFunc)
Py_DECREF(pFunc);
if(pArgs)
Py_DECREF(pArgs);
if(pRet)
Py_DECREF(pRet);


//PyGILState_Ensure();
Py_Finalize();




]]>python 发送http posthhttp://www.shnenglu.com/API/archive/2013/12/03/204566.htmlC++技术中?/dc:creator>C++技术中?/author>Tue, 03 Dec 2013 06:08:00 GMThttp://www.shnenglu.com/API/archive/2013/12/03/204566.htmlhttp://www.shnenglu.com/API/comments/204566.htmlhttp://www.shnenglu.com/API/archive/2013/12/03/204566.html#Feedback0http://www.shnenglu.com/API/comments/commentRss/204566.htmlhttp://www.shnenglu.com/API/services/trackbacks/204566.html1.新徏http.py如下Q?
import urllib
import urllib2
url 
= 'http://push.hao123.com/apis/test_send_msg.php'
values 
= {'g_id':'1027019902',
          
'm_time_to_send':'1386049369',
          
'm_display':'1',
          
'm_push_type':'2'
          ,
'm_by_timezone':'0'
          ,
'm_msg':'中华人民共和国万?/span>'
          ,
'mt_id':'0',
          
'm_iggid_file':'33600458'
         }
data 
= urllib.urlencode(values)
print data
req 
= urllib2.Request(url, data)
response 
= urllib2.urlopen(req)
the_page 
= response.read()
print the_page

注意以下包含中文Q需把文件另存ؓutf-8格式?br />然后执行Qpython http.py


]]> Ʒ99Ʒþ| Aݺݾþɫ| þþƷ99þ޶| ŷһþþƷ| þó˹Ʒһ| ƷžžþùھƷ| 97ȾþƵƷ99| re99þþƷ99| ŮþþŮ| ľþþƷ| ޹Ʒ18þþþþ| vaþþþ| ޡvþþ뾫Ʒ| þþƷ| ձ޷츾þþþþ| þۺ㽶AV| þ޹˾Ʒɫ| þþƷƷëƬ| þþƷ| Ʒ99þþþþö| ھƷþþþþþɬ| þۺϸۺϾþ| ޾þһ | 99Ʒþþþþþ| Ʒþþþþ| Ʒ99þþþƷ| ھƷþþӰԺ | Ʒþþ| һɫþ88ձȡۺ| һۺϾþ| ٸþĻ | þۺɫˮ99ž| ޾Ʒרþþ| 㽶þҹɫƷС˵| ۿƷþ| þþƷԴվ| Ʒþþþþþþþ| þþƷƷ޾Ʒ| þ99Ʒ| þþƷȫۿ| һþ㽶߿ۿ|