关于网络协议封装的一些新想法

最近业余时间在写一个小游戏。在为客户端封装socket层时头脑一热,有了一些新的想法, 在这里记录一下。 客户端使用的是Unity3d引擎。而在Unity3d中,基础的socket库只提供两种模式,一种是阻塞模式,一种是异步callback模式。 一般都需要基于这两种模式下进一步封装,才可以更方便的使用。 咨询了几个做客户端的并搜了一下,发现大家的惯用手法都是开一个线程去使用socket阻塞去读,然后把读到的数据通过队列传回主线程进行处理。 但是也许是单线程的思维模式已经深入我心了,所以我……

给silly增加热更新

最新抽了点时间给silly增加了一个silly.patch模块,用于对热更新提供一些有限的支持。 热更新最麻烦之处莫过于“数据迁移”, 即怎么使新函数(要更新的函数)以“运行时数据”的状态运行。 其实http这类无状态协议是最为简单的,因为他们不需要“数据迁移”的过程。http的这种架构,使得所有的函数都是无副作用的,所有的数据在请求结束给出Response的同时, 数据就已经存入了数据库。当需要热更新函数时,根本就不需要考虑数据的问题,直接替换就可以完美解决。 与此相对的是,通常的服务……

使用缓存优化数据请求

继上一篇场景之后,事情还没有完。 我有一堆struct obj对象(数量级可能为千级), 客户端需要频繁拉取这些信息中的一部分去显示(比如,当切换标签页时)。 由于这一操作可能会很频繁,而struct obj对象并不算小,如果每一次都重新拉取全部数据,有点让人不舒服,而且对流量也是一种很大的浪费。因此就琢磨着怎么去优化整个过程,以使在此过程中使数据传输量最小。 第一反应,肯定就是对整个列表加一个version字段,每当有obj对象改变时,version加1,当客户端进行拉取时,拿着他本地……

如何恢复全局INDEX

一般来说,当需要分配全局惟一id时,一般都会有一个变量来记录当前最新的id值,比如叫INDEX变量。 每次需要分配id时,只要简单的自增一下INDEX变量,然后INDEX的值即为当前分配出去的ID的值。 为了最大可能的延迟复用已经分配过的id,一般来说不会去特殊处理INDEX变量,即每次自增INDEX,并允许回绕情况的发生。 但是最近碰到问题就是,我有一堆分配过的id,如何重新恢复出INDEX的值。具体场景如下: struct obj { unsigned int id; time_t createtime; ……

为什么要有头文件

我在写C文件时,一般会首先确定这个模块需要哪些功能,然后在头文件中定义相应的接口函数。之后才是在C文件中实现,在实现过程中除非有遗漏的接口,不然是不会再切回头文件的,一般辅助函数我都是直接以static的方式定义在C文件中。 在写C++代码时,这些代码辅助类的函数,都必需要以private的方式在头文件中声明。这会导致在写代码时,需要频繁在h/cpp之间切换,极度令人不舒服。 因此每次在写C++代码时,都免不了在心里抱怨几句为什么不把private函数直接定义在cpp文件中,或者干……

Git之坑

最近在使用Git进行多人协作时遇到了一些坑,在些处记录一下。 在使用git的过程中,最频繁使用的应该就是git pull了。在git pull命令时,一般会遇到下面几种情况。 如果是本地完全没有修改,则可以顺利进行git pull,如果有本地提交会与git pull下来的commit进行自动merge(当然自动merge也有可能失败,手动解决一下冲突即可)。 如果本地的修改与被git pull下来的commit中修改有相同的文件,这时git会报错提示,这时只让你先把本地修改commit或stash一下,也不会有太大问题。 最坑的……

回首2016

16年初我又辞职了,即使在满足我的薪资要求的情况下。主要原因就在于,我的技术路线图受阻。 原本按我的打算,在有了少许高并发和socket经验之后,我需要进一下积累数据库使用实战经验。 然而在上家公司中,数据库部分操作是单独剥离出来,由java实现的。 而我所维护的C++部分仅仅处理高并发和正常的战斗逻辑并不涉及任何数据库部分。 因此,为了顺利继续我的技术路线图,我违反了自己的约定。 如果要找一个词来概括我2016年的大部分内容,那就是lua。 是的,正是由于这门语言,让我……

listen函数中的backlog字段

今天在公司无意间又拿redis-benchmark测了一下silly的IO并发性并与redis本身比较了一下。 发现在2000个client同时并发的情况下,性能只是Redis的30%的左右。 直觉上这很不正常,虽然silly所有的数据经过lua层时都需要malloc和memcpy,但最多性能上差个10%~20%就已经很可观了,绝对不可能差70%这么多。 通过不断的调整client的个数,我发现性能并没有明显随着client的数量降低而降低,而是在client个数到达某个值时突然降低的。 比如我自己测的数据是在491个client时,silly的性能与r……

如何做到宽容的收

在《unix编程艺术》提到过,Postel规定过:“宽容的收,谨慎的发”。 当时看到这一段话时,并没有多加思考,以为仅仅是对于网络协议多加检查就好了,并没有深想。 然而经过这两年的实践,我发现其实这条准则可以适用于更多的领域。 对于一个进程来说,他的输入可能是标准输入、管道、网络、配置文件等这些外部输入源。 那么进程所表现出来的宽容就是,不管从外部输入源接收到任何数据,都不应该影响程序的正常执行。即不会由于错误的数据格式或内容,造成崩溃,污然数据等副作用。 实……

数据加载策略

一般稍具规模的软件往往都少不了配置,游戏软件更是如此。 一个完整个游戏软件的配置数据往往有数MByte甚至更多, 完全加载进同内存往往需要几秒的时间。 几秒钟听起来不长,然而如果是在客户端刚打开时加载,这点延时却时致命性的,因此必须将配置的加载速度优化到足够快。 其中一种办法是在实现细节上做文章。 假设配置表为xml格式,我们可以在打包前优化配置文件的结构。 比如可以在使用xml文件之前,将所有xml文件拼接成一个文件,会提高不少加载速度。这是因为使用一个文件包……