元旦前面几天都在忙着面试,随后的几天也就一直在做服务端基础库开发方面的工作.对于服务端开发,是很久之前的事情了.那时候我还在大学读书,一直都是在倒腾服务端开发方面的东西,毕业后参加公司工作就是一直从事客户端开发工作,再也没有碰过服务端开发的事情.刚开始我很犹豫,不过一切并没有想象的那么糟糕,很快我就找回了以前的状态,总体来说,这几天的工作成果和效率我还算是满意的.最主要的是状态回来了,所以也就不担心其他的了.
先说一下为什么我要选择自己去开发服务端的基础库.总体来说,自己去开发服务端,从零开始,在stl和posix thread上面去开发自己的基础库是很有难度的,会遇到很多的问题.我之所以这样子选择,是因为对于优秀源码库阅读量比较多,自己比较自信,即使遇到一些设计实现上面的问题,我也可以很快找到优秀的实现源码,第一时间去参考别人的设计实现方法.另外,和我选择开发的底层语言也是相关的,我这次并没有选择使用C,也没有选择使用C/C++混编,除了底层系统级别的C库之外,我都是使用全C++方式开发的,基础的思维方式也是面向对象.我承认,自己系统学习C++理论知识的时间还很短,可是在实际的开发过程中,我发现已经足够支撑我前进了.唯一不足的就是,我需要做大量的傻瓜方式的测试才能保证自己写的底层模块在执行的流程上面不出现错误,当然这是在不涉及复杂业务逻辑的时候.对于需要处理复杂繁琐逻辑的地方,我都是无条件的信赖stl.在这一层面,我并没有选择自己去做无畏的工作,主要还是我相信我没有能力涉及到那个层面.
之所以选用C++去开发,而没有选择java/erlang/golang之类的语言,不是因为我真的不会这些快餐式的语言.说白了,还是心底的固执与偏执在作祟,其他的应该就不用多说了.其实我完全是可以选用java/golang的,java开发起来对我来说难度并不大,即使已经好久没有碰过,也不知道现在最新版本的JDK更新到哪里了,我想这些都不会影响我的.对于java方式的开发,我更愿意承认那是各种第三方组件的混合物,问题说到最后就只是如何快速学习和正确使用这些第三方开发组件罢了.而golang作为现在很有竞争力的C系语言,我还是很喜欢的,但是我怕自己还不能正确理解它的工作方式,那将直接影响我对它的使用理解.即使能做出来东西,在理解不正确的情况下,相信也拿不出手.
当然,从前面的一些文章我就开始暴露出自己很久不碰服务端开发的问题了.但是也都一一解决了.让我感到很恼火的是,我在Ubuntu Kylin上面开发,用CMake管理项目,用sublime去写代码,而sublime总是会莫名其妙的死掉,还好的是,给我造成的代码丢失每次都并不是很多,也可能是我喜欢疯狂保存(C-S).当make不过或者是执行test/sample发现逻辑有问题的时候就到qtcreator/kdevelop去调试.总体来说,这个流程我渐渐的熟悉并习惯,做起事情来也算是比较的顺手,当然依靠unittest和sample,由于其简单业务逻辑的限制,我相信可能会有一些问题是发现不了的,不过这没有关系.我可以在开发后端应用的时候遇到问题,在开发中解决.
在开发之前我曾经仔细想过,并对自己做过一些简单要求.不使用隐晦难懂的语法,不依赖继承,接口设计尽量多而简单.这些是我对自己提的要求,也是为了在设计底层接口的时候提醒自己.这几天编码下来,我都是尽量遵循这些规则在实现方面下工夫.需要提的一点是,我受到golang的影响,在实现中很少使用继承,而是更多使用简单的组合功能.当然了,我也不是什么完美主义者,并不是完全要求自己写出完全按照自己要求的那些代码,我还是会使用接口方面的功能.就像是纯虚类之类的来作为接口.就像是线程执行的任务,我就直接采用了以前我使用java的那种方式,设计了一个Runnable的接口,提供一个run方法由任务子类自己去实现.这样做也是很方便的.其他的还有很多,例如,自己实现的简单的引用计数的智能指针,其中包括类似stl的std::autoptr以及boost::sharedptr这样的指针,说到实现的话,里面使用的引用计数我就是使用了gcc的原子操作做到的.细节就不说了,这方面的资料可以自行去Gnu gcc查阅官方的一手资料.网上的二手资料也很多,可以很容易找得到的.
在这几天的编码中,主要是实现了基础的一些功能,大部分的时间都花在实现锁处理,线程,线程以及线程池上面了,另外还简单的处理了一下时间,但是并没有处理日期.这个延后做吧,至少我现在的需求对日期方面的处理还没有依赖.今天早上也是在着手处理网络部分的模块.由于发现自己对ip地址的格式处理根本就没有任何的经验,所以不得不暂停了网络库部分的开发,转而去了解这方面的知识,希望今天可以补足ip格式处理方面的基础功能.另外我也考虑过了,由于我开发网络库部分是为了游戏服务端服务的,暂定的实现方式是使用reactor-aceptor的工作方式,在reactor采用epoll去管理socket io事件,对于长链接,则是提供直接创建service工作方式,基础接口我会直接给出,由上层根据业务需求自己去实现.而这部分直接实现runnable,提供独立的线程去处理r-a服务.也就是处理epoll io事件.长链接建立之后所有的任务都应该进到任务队列去,由线程池的工作线程处理.工作线程之后可以说,应该就到业务逻辑部分了.不过我不打算完全用C++开发,所以肯定会用脚本语言.至于是选用Lua还是Python再看吧.
其实按照这种分析方式来说,从socket管理到任务队列再到工作线程分发任务到具体服务还是脚本,这些可以认为是与下层服务无关的,这部分既不会对通信数据进行操作,也可以从下层服务独立出来.就是通信调度部分.也可以说是服务端调度的核心层.接下来要考虑的事情就是,将通信部分独立出来之后,到服务之后,服务之间的通信问题.如果我将服务间的通信都丢到任务队列去,由工作线程处理的话,那么需要做的就是自己独立设计一套通信方式用来区别本地通信和客户端到服务端请求(c2s-client to server).