本文作者:sodme
本文出处:http://blog.csdn.net/sodme
声明:本文可以不经作者同意任意转载,但请保留文章开始前的作者、出处及声明信息。谢谢。
由于个人工作的关系,接触高性能服务器的研发已经有一段时间了,在没有接触这个话题之前,我也和许多人一样,认为服务器的设计无非就是用一下winsock,调用调用函数那么简单。当亲自完成了一个在win平台上能承载上万连接的测试模型后,才知道,原来,作高性能服务器是这么有挑战性。你不仅需要在细支末节上对模型进行精雕细琢,更需要在总体架构方面进行权衡选择。这两方面,都会影响到你的服务器性能的正常发挥。作为对“细枝末节”方面的介绍,请参照我之前写的系列文章“完成端口之性能优化”。而从此篇文章开始的系列文章,将就一个完整的高性能服务器模型进行介绍,而对于服务器集群架构方面,则不在此系列的讨论范围,那将是未来数周我将要完成的事。有朋友跟我说,希望我能提供底层模型的完整代码或可供使用的动态链接库及LIB文件。对于这个要求,我现在还在考虑之中。确实,有了代码,要学得更快一点,但由于模型里牵涉到一定的版权问题,所以,我会考虑将其进行必要的修改,而后再考虑是否向大家提供源代码。不过,可以肯定的是,对于LIB及DLL的要求,我想我会尽快提交上来的。
所谓的“高性能”,我想不外乎两个方面:
1、处理的并发请求要尽可能地多,具体表现为同一时间内同时连接的客户端数量;
2、数据包的吞吐量要尽可能地大,具体表现为单位时间内服务器的收、发数据量。
win平台下,IOCP(完成端口)是处理大量并发连接的最佳处理方案,所以,此后讨论的文章,也是基于这个模型的。有关一个独立的IOCP模型到底是如何工作的,请大家下载微软的SDK,在那个例子里,有基本的IOCP示例。但那仅仅是个示例,于实际的应用中,还需要作很多工作。阅读以下的内容时,最好具备以下条件:知道IOCP的基本概念,以及它所调用的几个必备函数(Create、Get、Post函数等)的使用。注:为嫌麻烦,这几个函数,我采用的都是简单叫法,完整的函数名请查看完成端口相关资料。
为了使大家能有一个宏观概念的把握,我先介绍一下基于三层结构的服务器通信底层模型。对于软件架构而言,没有最好之说,放在不同的应用环境其表现都可能千差万别,所以,我不保证这个架构是能让所有人都看着舒服的,我只保证,在我当前的项目应用中,这个架构充分考虑了“性能”和“可扩展性”两者的兼顾,让我在很容易地开发新的服务器时,仍然可以享受到很好的性能。
一、三层架构图及简单说明
三层架构图如下:
CIOCPServer
||
||
CCutomHPServer
||
||
CTestServer
以后我们要讨论的就是这个看上去并不复杂的三层架构图,下面就此架构图中的主要类进行简要说明。
CIOCPServer:
完成端口服务器基本通信类,它使用winnt/2000/xp平台特有完成端口特性,对通信模型进行封装,向它的派生类提供以下基本扩展接口(可被重载的虚函数):
1、有客户端连接时的处理接口;
2、客户端断开时的处理接口;
3、从客户端收完数据后的处理接口;
4、向客户端发送完数据后的处理接口;
5、网络通信及服务器处理出现错误时的处理接口。
CCustomHPServer:
典型的高性能服务器类,CIOCPServer是其基类之一(之一?难道还有另外的基类,回答是:当然,呵呵,别急,后面会介绍),此类在CIOCPServer的基础上,封装了三个数据队列及三类处理线程,介绍如下:
1、接收数据包队列及接收线程:用于存放刚收到的数据包,此数据包还没有进行逻辑意义上的拆解,接收线程从此队列中取出数据包,并将其形成一个逻辑意义上完整的数据包加入到“处理数据包队列”中;
2、处理数据包队列及逻辑处理线程:已经拆解成了逻辑意义上的数据包,逻辑处理线程对此类数据包进行逻辑解析,这里就是服务器的主要逻辑部分,有的数据包在处理完成后,可能是需要向客户端返回处理结果的,此时就需要逻辑线程在处理完成后将返回结果的数据包放入“发送数据包队列”中;
3、发送数据包队列及发送线程:待发送的数据包队列,由发送线程根据数据包里的客户端套接字发送给特定客户端。
CTestServer:
此类是一个测试类,主要用于演示如何在CCustomHPServer的基础上派生一个真正的应用服务器,并用于说明它需要重载实现CCustomHPServer的哪些重要虚函数。
基于以上的结构,我们的服务器通信模型,可以一层一层地实现,一层一层的测试。在CIOCPServer中,它本身是不带有任何数据队列的,所有的网络数据都是即来即处理,没有保存数据,实现的是即时响应。在CIOCPServer里,有两类重要线程:AcceptThread线程和WorkerThread线程。其中,AccetpThread线程使用Accept或AcceptEx函数来接收客户端的连接请求,并实现客户端socket与完成端口句柄的绑定,“有客户端连接时的处理接口”就是在这里封装的;而WorkerThread线程是我们在完成端口中常说的“工作者线程”,它由get函数触发工作,除“有客户端连接时的处理接口”之外的其它接口,都在这里进行封装。
在真正实现一个高性能服务器模型时,我们可能需要逐层地加以实现,这样作,一是因为测试起来要简单一些,二是因为在我们逐层实现时可以清楚地知道每一层在实现时的效率是什么样的,这样就有利于我们找出提高效率的突破口。可以先从CIOCPServer类开始,实现一个简单的ECHO服务器,即:回显服务器。不用维护数据包队列,对客户端发过来的数据,即时返回给客户端。作完这一层,属于完成端口该作的事基本上就作完了,它包括:有大量客户端连接时的客户端连接队列维护,客户端连接、断开、发送、接收数据时的事件处理及线程同步。根据我的经验,在处理底层的客户端断开事件时是一个难点,新手往往会在接收到断开事件时直接释放掉当前客户端对象,但比较好的作法是使用引用计数机制,而不是直接释放。另外,在“释放”这一点上,我也有自己的一个看法,即:客户端对象最好不要释放,而把它放入闲置队列或者关闭原来的socket之后,再重新生成一个新的socket让它与原客户端对象关联,把它作为一个新的客户端对象使用,这样就避免了频繁的客户端对象的建立与释放,当然,这样作的前提是在接受客户端连接方面最好使用AcceptEx函数而不是Accept。
这篇文章里,仅就模型的总体结构进行了介绍,关于这三个类的具体实现及片段代码,会在下篇文章里介绍,请继续关注,也请有兴趣的朋友能在我的Blog里反馈你们的意见。
<未完待续>
评论
- #shadowfish 发表于2005-07-03 23:35:00 IP:
- TrackBack来自《基于win平台的高性能服务器底层通信模型设计(1) 》:
Ping Back来自:blog.csdn.net
- #jzbase 发表于2005-06-12 15:23:00 IP: 61.186.252.*
- codeproject有个基于IOCP的echo服务器的例子
- #Luca2005 发表于2005-07-04 11:38:00 IP: 61.186.252.*
- 不错,等着你接下去的文章
- #redchina 发表于2005-07-17 19:20:00 IP: 61.186.252.*
- 欢迎探讨~~~
- #Rewow 发表于2005-07-15 07:05:00 IP: 61.186.252.*
- 你提供的这个win服务器模型的代码是delphi还是C++的呀?期待ing
- #sodme 发表于2005-07-17 11:00:00 IP: 61.186.252.*
- to qes:
这位兄弟既然知道我作过棋牌,也应该知道我现在正在从事哪方面的工作。你认为MMORPG与休闲游戏在底层通信模型方面的要求会有很大区别吗?难道休闲游戏就只配用最简单的模型而只有MMORPG才配用最复杂的完成端口?不要鄙视人家棋牌游戏,说不定哪天人家QQ游戏收了你的公司都还不一定呢。
- #初学者请教 发表于2005-07-18 13:20:00 IP: 61.186.252.*
- 不知道sodme的服务器端是使用独立的服务器就是单独的如登陆服务器loginserver.exe+DBSvr.exe数据库服务器+Logingate.exe逻辑服务器来组合完成网络游戏服务器端的全部功能吗?请不吝指教。
- #sodme 发表于2005-07-18 17:08:00 IP: 61.186.252.*
- 是的,对于具有独立功能的服务器,是按单个进程来作的。登录服务器,场景服务器以及网关服务器等都是不同的程序。程序间使用socket通信。
- #初学者 发表于2005-07-19 00:07:00 IP: 61.186.252.*
- 您现在做的MMORPG和以前做的棋牌网络游戏也是几乎同样的以单独多进程服务器来分别完成各自的功能模块而以sock作为通讯手段吗?
- #sodme 发表于2005-07-19 09:10:00 IP: 61.186.252.*
- 休闲棋牌游戏的通信量不大,所以,用的一个逻辑线程作的游戏逻辑。MMORPG目前采用的也是单独的一个逻辑线程作游戏逻辑,对于游戏逻辑中比较耗时的部分会提练出来交给另外的专用线程去作,比如游戏的AI,数据库的读写等。
- #sodme 发表于2005-07-19 09:13:00 IP: 61.186.252.*
- 游戏AI是单独的进程作的,不是线程。呵呵。
- #初学者 发表于2005-07-20 05:23:00 IP: 61.186.252.*
- 您现在mmorpg里用的是线程还是进程?不会是两个同时使用吧。还是用delphi写服务器端程序吗?谢谢!
- #初学者 发表于2005-07-20 05:27:00 IP: 61.186.252.*
- 以上指的是MMORPG网络游戏的AI部分(实现是用单线程还是使用多进程)。不好意思。
- #sodme 发表于2005-07-20 08:50:00 IP: 61.186.252.*
- 进程,请不要再问我关于我参与的项目的细节问题,以后不再回答。单独的技术讨论可以,但我拒绝讨论我参与的项目细节,因为项目尚在实施中,现在还不是讨论的时候。
- #继续学 发表于2005-07-19 15:48:00 IP: 61.186.252.*
- 对于您现在MMORPG的设计有些迷惑。就是说你们采用的是混合的模块方式工作,即有使用多线程的部分,而游戏AI采用的又是单独的线程实现(单独的exe),架构是这样子的吗?你们的MMORPG服务器是用C++全部实现的吗?
- #sodme 发表于2005-07-19 18:12:00 IP: 61.186.252.*
- 游戏AI的计算是比较耗时的,通常有两种作法:一种是在场景服务器上,开设专门的线程负责计算怪物AI,另一种是作一个单独的AI服务器,场景上所有的AI计算全部丢给这个AI服务器去计算,它计算完后把结果返回给调用者服务器。
- #sodme 发表于2005-07-20 11:31:00 IP: 61.186.252.*
- to 初学者:
呵呵,没关系,只要不再直接问我有关项目细节的问题就好,有问题我们也可以在MSN上聊。公司项目是集体智慧的成果,我没权利一个人把它们公开。单说技术,我基本上会有问必答的(自己不懂的除外,哈哈)。^_^
|