流媒体服务器架构知识

2024-09-24

流媒体服务器架构知识(共7篇)

1.流媒体服务器架构知识 篇一

现在许许多多的初学者和程序员,都在趋之若鹜地学习Web开发的宝典级框架:Struts2,Spring,Hibernate。似乎这些框架成为了一个人是否精通Java,是否会写J2EE程序的唯一事实标准和找工作的必备基础。

然而,如果在面试的时候问这些程序员,你们为什么要学习这些框架?这些框架的本质到底是什么?似乎很少很少有人能够给我非常满意的答复。因为他们都在为了学习而学习,为了工作而学习,而不是在真正去深入了解一个框架。其实所有的人都应该思考这样的问题:为什么要学习框架?框架到底给我带来了什么?接下来,我们以登录作为一个最简单的例子,来看看不同的年代,我们是怎么写Web程序的。目 录 [-]

1.后来,我们放弃了在页面上写逻辑 2.在很多年前,我们这么写程序的 3.再后来,出现框架 4.我们到底要什么

后来,我们放弃了在页面上写逻辑

后来,程序写得越来越多,我们发现,这种在HTML代码中编写Java代码来完成逻辑的方式存在着不少问题:

1.Java代码由于混杂在一个HTML环境中而显得混乱不堪,可读性非常差。一个JSP文件有时候会变成几十K,甚至上百K。要找一段逻辑,经常无法定位。

2.编写代码时非常困惑,不知道代码到底应该写在哪里,也不知道别人是不是已经曾经实现过类似的功能,到哪里去引用。

3.突然之间,某个需求发生了变化。于是,每个人蒙头开始全程替换,还要小心翼翼的,生怕把别人的逻辑改了。

4.逻辑处理程序需要自己来维护生命周期,对于类似数据库事务、日志等众多模块无法统一支持。

在这个时候,如果有一个产品,它能够将页面上的那些Java代码抽取出来,让页面上尽量少出现Java代码,该有多好。于是许多人开始使用servlet来处理那些业务逻辑。Java代码

1.public class LoginServlet extends HttpServlet { 2.3./*(non-Javadoc)4.* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)5.*/ 6.@Override

7.protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { 8.String message = null;9.RequestDispatcher dispatcher = req.getRequestDispatcher(“/result.jsp”);10.String name = req.getParameter(“name”);11.String password = req.getParameter(“password”);12.13.UserHandler userHandler = new UserHandler();14.if(userHandler.authenticate(name, password)){ 15.message = “恭喜你,登录成功”;16.} else { 17.message = “对不起,登录失败”;18.} 19.20.req.setAttribute(“message”, message);21.dispatcher.forward(req, resp);22.} 23.}

在这里,我们需要在web.xml中为这个servlet配置url的请求关系。Xml代码

1.

2.Login 3.

4.com.demo2do.servlet.LoginServlet 5. 6.

7.

8.Login 9. 10./Login 11. 12.

代码重构到这里,我们发现,其实我们的工作量本身并没有减少,只是代码从JSP移动到了Servlet,使得整个流程看上去稍微清楚了一些。然而,为了这么点干净,我们付出的代价是什么?为每个servlet都在web.xml里面去做一个url的请求配置!

在很多年前,我们这么写程序的

很多年前,那是一个贫苦的年代,如果我们要使用Java在网页上做一些动态的交互功能。很多人会告诉你一个技术,叫做JSP。在我还对Java非常困惑的时候,就有人告诉我,JSP是个好东西,它可以在HTML代码里面写Java代码来完成逻辑。Html代码

1.<% 2.String name = request.getParameter(“name”);3.String password = request.getParameter(“password”);4.5.UserHandler userHandler = new UserHandler();6.if(userHandler.authenticate(name, password)){ 7.%>

8.

恭喜你,登录成功

9.<% 10.} else { 11.%>

12.

对不起,登录失败

13.<% 14.} 15.%>

作为一张JSP,它可以接收从别的JSP发送过来的登录请求,并进行处理。这样,我们不需要任何额外的配置文件,也不需要任何框架的帮忙,就能完成逻辑。

再后来,出现框架

时代进一步发展,人们发现简单的JSP和Servlet已经很难满足人们懒惰的要求了。于是,人们开始试图总结一些公用的Java类,来解决Web开发过程中碰到的问题。这时,横空出世了一个框架,叫做struts。它非常先进地实现了MVC模式,成为了广大程序员的福音。

struts的代码示例我就不贴了,网上随便搜搜你可以发现一堆一堆的。在一定程度上,struts能够解决web开发中的职责分配问题,使得显示与逻辑分开。不过在很长一段时间内,使用struts的程序员往往无法分别我们到底需要web框架帮我们做什么,我们到底需要它完成点什么功能?

我们到底要什么

在回顾了我们写代码的历史之后,我们回过头来看看,我们到底要什么?

无论是使用JSP,还是使用Struts1,或是Struts2,我们至少都需要一些必须的元素(如果没有这些元素,或许我还真不知道这个程序会写成什么样子):

1.数据

在这个例子中,就是name和password。他们共同构成了程序的核心载体。事实上,我们往往会有一个User类来封装name和password,这样会使得我们的程序更加OO。无论怎么说,数据会穿插在这个程序的各处,成为程序运行的核心。

2.页面展示

在这个例子中,就是login.jsp。没有这个页面,一切的请求、验证和错误展示也无从谈起。在页面上,我们需要利用HTML,把我们需要展现的数据都呈现出来。同时我们也需要完成一定的页面逻辑,例如,错误展示,分支判断等等。

3.处理具体业务的场所

在这里,不同阶段,处理具体业务的场所就不太一样。原来用JSP和Servlet,后来用Struts1或者Struts2的Action。

上面的这些必须出现的元素,在不同的年代,被赋予了不同的表现形式,有的受到时代的束缚,其表现形式非常落后,有的已经不再使用。但是拨开这些外在的表现形式,我们就可以发现,这不就是我们已经熟门熟路的MVC嘛?

数据 ———— Model 页面展示 ———— View

处理具体业务的场所 ———— Control

所以,框架不重要,概念是王道。只要能够深刻理解MVC的概念,框架对你来说,只是一个jar包而已。

MVC的概念其实就那么简单,这些概念其实早已深入我们的内心,而我们所缺乏的是将其本质挖掘出来。我们来看看下面这幅图,这是一副流行了很多年的讲述MVC模型的图:

在这幅图中,MVC三个框框各司其职,结构清晰明朗。不过我觉得这幅图忽略了一个问题,就是数据是动的,数据在View和Control层一旦动起来,就会产生许多的问题:

1.数据从View层传递到Control层,如何使得一个个扁平的字符串,转化成一个个生龙活虎的Java对象

2.数据从View层传递到Control层,如何方便的进行数据格式和内容的校验?

3.数据从Control层传递到View层,一个个生龙活虎的Java对象,又如何在页面上以各种各样的形式展现出来

4.如果你试图将数据请求从View层发送到Control层,你如何才能知道你要调用的究竟是哪个类,哪个方法?一个Http的请求,又如何与Control层的Java代码建立起关系来?

除此之外,Control层似乎也没有想象中的那么简单,因为它作为一个控制器,至少还需要处理以下的问题:

1.作为调用逻辑处理程序的facade门面,如果逻辑处理程序发生了异常,我们该如何处理?

2.对于逻辑处理的结果,我们需要做怎么样的处理才能满足丰富的前台展示需要?

这一个又一个问题的提出,都基于对MVC的基本概念的挖掘。所以,这些问题都需要我们在写程序的时候去一一解决。说到这里,这篇文章开头所提的问题应该可以有答案了:框架是为了解决一个又一个在Web开发中所遇到的问题而诞生的。不同的框架,都是为了解决不同的问题,但是对于程序员而言,他们只是jar包而已。框架的优缺点的评论,也完全取决于其对问题解决程度和解决方式的优雅性的评论。所以,千万不要为了学习框架而学习框架,而是要为了解决问题而学习框架,这才是一个程序员的正确学习之道。

2.流媒体服务器架构知识 篇二

对广电运营商来说, 随着跨网多屏全媒体战略的实施, 运营商将获取更多的内容分发渠道、更大的用户规模;随着用户的急剧增多, 视频内容需求量将增大, 内容格式转换和内容存储能力需求将急剧增加, 内容分发网络也需要具备跨网络、自适应等特性, 还要解决自动适配问题以确保多屏一致的用户体验。传统的分发网络、内容平台、内容资源、适配转码技术等不能满足归一化内容加工、承载和发布的需求, 只有发展云计算平台, 才能更好地解决目前困扰业界的规模和成本问题, 实现合理分工、各有所长、各取所需、快速发展。

基于各地各类宽带网络建设和带宽提升, 以及互联网云计算基础产业的蓬勃发展日渐成熟, 可以构建一个无差别统一加载应用的开放平台产品。借鉴互联网的优势规模效应, 引入海量应用, 方便适配区域网络、终端带来的差异化, 为终端用户提供统一的业务接入能力。

2互动媒体云服务平台的定义

互动媒体云服务平台利用云计算技术, 在云端统一加载互联网、游戏、办公、通讯、社区等智能应用, 对各类应用进行统一编码流化处理, 并提供统一流媒体服务, 利用终端的解码能力进行业务无差别体验, 终端无需升级即可方便体验3D、视频、跨网、跨屏等高品质应用。云平台将无差别地服务于有线、宽带、3G等网络的PC、TV、Pad、手机等多种终端。

3整体架构设计

互动媒体云服务平台整体架构设计如图1所示。云平台能够为运营商提供云视频化的统一服务, 包括普通应用进行流化的通用承载与第三方流服务能力 (如VOD、云游戏等) 的统一调度, 对业务提供非视频应用和视频应用的接入, 对终端提供交互终端、单向终端的接入。

3.1与其他运营平台的关系

(1) 与基础运营商及其运营平台的关系

基础运营商负责对终端用户进行终端发放、维护及费用收取, 云平台可以作为数字电视基础平台之上的二级应用承载及运营平台, 进行业务引入、用户业务运营, 并通过与基础运营商的BOSS系统对接, 实现业务的计费与分账, 并提供基础运营商统一的运营支撑、运维管理接口对接能力。

(2) 与互联网、移动互联网及其运营平台关系

可与互联网、移动互联网的系统对接, 实现移动互联网的终端及业务跨网、跨屏接入。并可通过平台实现业务引入、业务合作运营、业务对账功能。

3.2平台具备的能力

3.2.1应用接入能力

(1) 非视频应用

以Web、Java、Flash及其他桌面应用为主, 应用本身不具备提供服务的能力, 由云平台进行应用环境准备并进行虚拟化并行承载, 并通过编码系统提供流化输出。

(2) 视频应用

包括VOD、DVB、时移、云游戏等直接提供流服务的应用。对于此类应用, 云平台主要进行资源调度与接口对接。

3.2.2终端接入能力

(1) 交互终端

本身提供上下行IP的链路条件, 在这种模式下, 指令与键值均通过上下行IP链路进行交互, 支持红外rc、键盘、鼠标、手柄等外设。

(2) 单向终端+外交互

由外交互设备 (Wi-Fi-rc、手机、Pad等) 提供指令、键值的上行, 再通过DVB指令通道下发指令到终端, 终端进行频道切换提供服务。

3.2.3基础运营对接能力

(1) 支持与BOSS对接

与BOSS进行用户信息的同步, 并接收BOSS发送来的终端绑定、用户授权等信息, 也提供与BOSS之间通过接口进行用户、业务的认证授权。

(2) 支持与网管系统对接

与运营商网管系统之间提供硬件、OS层面的接口对接, 也可提供软件层面的局部信息的查询与管理服务。

(3) 支持与前端系统对接

云平台需要通过复用器进行全频点DVB指令下发, 通过IPQAM进行视频流的数据下发, 通过IPQAM进行数据端口指令复用, 进行DVB局部频点指令的下发。

3.2.4互联网、移动互联网接入能力

(1) 手机/Pad

云平台目前把手机、Pad等外设看做另外的浏览屏幕与键值终端, 可通过手机、Pad进行内容浏览后, 发送服务指令给云平台, 由云平台提供视频服务。也可模拟键值终端。

(2) 互联网SP

云平台同时也支持一些互联网应用进行局部修改后接入, 因此也提供与互联网应用、SP的接口对接关系。

4功能架构设计

如图2所示, 应用视频云平台内部分为5大平台, 分别是:视频云服务平台, 提供应用承载与编码流化服务;云应用接入平台, 提供云服务的调度与管理服务;网络资源调度平台, 提供IPQAM等资源的管理与调度服务;云终端接入平台, 提供终端的上下行指令的传递与适配服务, 提供键值的上行传递与标准化服务;云服务支撑平台, 提供云服务的支撑、管理、运维等系统对接与管理手段。

(1) 视频云服务平台

如图3所示, 视频云服务平台是一款为多类型终端及外设、多用户提供并行接入, 并提供网页与桌面小应用的无差别终端体验能力的云服务承载平台系统产品。在终端接入与退出过程中提供应用承载资源管理、调度及分配能力, 提供视频编码资源管理、调度及分配能力, 提供应用展现与交互的多终端类型适配能力, 提供用户运行状态会话资源管理控制能力, 提供应用运行与用户控制能力。具备大规模集群系统的可靠运行性, 服务能力横向扩展性, 批量安装、卸载及升级的方便快捷性, 系统运行的资源容灾性, 并提供集群运行状态监控、查询、告警等功能。

(2) 云应用接入平台

如图4所示, 云应用接入平台是一款提供总体控制终端业务接入、应用及云服务接入、综合网络资源统一调度控制、运营支撑统一调度的中心控制系统产品。负责为用户的各类终端接入并切换于不同的云服务场景之间提供逻辑控制手段, 集中处理并维护用户在运行时的状态, 以及使用云服务资源与占用的周边网络系统资源状态。提供各类运营商既有VOD、DVB等业务控制适配能力。提供互联网应用电视转换网关, 将互联网应用转换成TV可操作的模式, 并能够与云平台对接。该平台是整体云服务平台的核心控制单元, 具备高并发低时延响应请求、7×24高可靠性运行保障、具备用户访问规模的横向扩展能力。

(3) 网络资源调度平台

如图5所示, 网络资源调度平台是一款为云平台提供应用交互与业务传输过程所使用到的边缘网络资源的管理、调度与控制能力的平台产品。提供对中心与边缘的二级资源的管理与控制、支持按业务种类进行不同资源分配能力、提供对用户终端的资源占用状态的管理与控制。具备资源分配与调度的高并发、高性能特性, 具备系统运行的高可靠性, 具备用户资源占用数据的高可靠性保存及高效恢复能力。

(4) 云终端接入平台

如图6所示, 云终端接入平台是一款为云平台提供机顶盒、Pad、PC、Phone等终端、基于IP、DVB、移动等异构网络的统一接入、交互、控制的系统产品。提供用户的多地市、多终端的统一接入能力, 为多用户不同的终端与外设提供统一并行的业务交互控制能力, 为云平台提供统一的多地市、多节点的终端寻址能力, 为不同终端提供多业务场景的模式切换能力及终端功能调用能力, 提供针对复用器的TS封装的广播指令转发和针对IPQAM的IP封装的点播指令转发。支持系统的高可靠性、高并发、高效率的运行特性, 支持系统响应能力的横向扩展性。

(5) 云服务支撑平台

如图7所示, 云服务支撑平台是一款为运营商支撑系统提供用户功能开通、话单输出等运营功能对接的系统产品。提供终端用户信息与订购管理、云接入认证、服务功能开通控制、用户云接入话单与各类云业务的用户使用话单汇聚输出的功能。须具备高并发、高可靠、高效率的用户认证能力, 提供用户订购状态、用户云接入话单、云应用业务话单等信息的高可靠性保持、备份、恢复与管理能力。

5结束语

不论存量机顶盒还是新发机顶盒, 按照传统业务运营模式, 都将面临硬件赶不上业务发展的问题, 带来升级代价大的现实问题, 必将影响应用的部署速度。通过基于云化架构的服务平台的构建, 把大量业务全部汇聚到中心端, 可以发挥云服务的规模优势、可以极大地丰富业务形式、可以大大降低业务落地部署的难度。但相对的, 对传输网络的要求也相应提高, 所有的业务都需要由终端通过高速宽带网络与中心端互通。具体如何取舍, 需要广电运营商根据自身的发展需求来决定。

参考文献

[1]范元正.广电云的研究与规划.电视工程, 2011 (04) .

[2]杨勇.广电云建设的探索和思考.视听界, 2014 (03) .

3.流媒体服务器架构知识 篇三

关键词:新媒体;大学生;陶瓷文化作品;知识产权;服务

随着社会的快速发展,文化产业与信息产业已经成为新世纪重要新兴产业,并成为了经济新的增长点,习近平总书记治国理政中,也强调以“六个一”为主体内容的基本思路。因此,在新媒体环境下,运用知识产权来进一步服务大学生陶瓷文化的探索与实践更具有理论意义和实践价值。

1 新媒体与陶瓷文化知识产权

随着社会的不断发展与进步,人类由竹简、印刷、电子符号向数字时代发展,传统媒介发生了很大变化,并由传统报纸、录音机、电视向以网络、手机为媒介的微媒体、自媒体时代发展。

在新媒体时代,通过运用新媒体技术,信息传播速度快、内容广、视觉震撼力和表现力较强。同时,新媒体一方面在向人们高速、快捷传递信息的同时,另一方面也出现了不容忽视的问题:实时监控难、证据采集难等,现行形势下陶瓷文化艺术品市场上作品真伪难辨、优劣不明,如何加强新形势下陶瓷文化知识产权保护工作就成了需要解决的现实问题。陶瓷产业在新媒体平台上的推广,从以往主要依靠手摸眼看的传统鉴定办法转换到用数据来表达、让科学来证明等,国家针对新媒体特别是互联网先后也出台了法律法规,并努力基于传统的知识權保护手段上,采用包括专利、商标和版权学在内多种方式,在知识产权保护方面,将更具计划性、战略性和前瞻性,为新媒体环境下大学生陶瓷文化作品知识产权服务开拓全方位、多层次、立体化空间,注重品牌塑造,加强陶瓷知识产权保护,维护陶瓷文化品牌。

2 新媒体环境下大学生陶瓷文化知识产权服务平台措施

第一,多元参与服务平台——从运用、保护和管理体制入手:鼓励发明创造,专利申请,维护陶瓷知识产权合法权益,完善知识产权工作体系。

通过政策引导和物质投入,带动增强知识产权意识,鼓励开展技术创新,加强对知识产权工作的进一步开展。在景德镇市调研过程中发现,通过颁布实施《专利费资助暂行办法》,设立市专利费资助资金等方式,比较好地调动了陶瓷人才开展技术创新、申请专利保护的积极性。

为进一步加强对陶瓷知识产权的保护,促进《景德镇陶瓷知识产权保护办法》顺利实施。严格开展专项执法检查,开展大型宣传咨询和打假活动,维护市场经济秩序,全面清理已办理使用“景德镇”驰名商标的100多家陶瓷企业,通过新闻媒体曝光严重侵犯陶瓷商标权的生产经营企业和个人;对于严重侵犯陶瓷商标权屡教不改的,可运用法律手段打击商标侵权行为。2006年11月28日,中国陶瓷知识产权信息中心举行了揭牌仪式,自2007年以来,全国陶瓷行业唯一一家知识产权信息中心在景德镇高校正式建立,景德镇通过该中心创办的“中国陶瓷知识产权信息网”,为中国陶瓷行业提供国内外专利的咨询、查找等各种服务,建立景德镇陶瓷专利信息数据库,建立健全了江西省陶瓷知识产权维权援助工作站,完成专利查新70余件,代理申请专利数百件,参与指导企业贯标50余家,建立建成专利专题数据库近百个。

第二,共聚智慧服务平台——推动创意创新创业教育,提升大学生知识产权应用能力,增强知识产权保护意识。

“4·26知识产权进校园”咨询是一项特色活动,由江西省陶瓷知识产权信息中心联合景德镇市科技局等部门,在景德镇陶瓷大学图书馆联合举办。景德镇每年承担中国知识产权培训中心的“全国陶瓷行业知识产权高级管理人员系列培训班”,通过建设专利管理信息平台,深入企业开展专利信息利用培训。

中国知识产权培训中心开通远程教育平台景德镇陶瓷大学分站,培养专利代理人。近年来,中心承办陶瓷领域及专利信息培训19次,培训人员2000多人次,远程教育培训3700多人次,承担全国高校巡回讲座3次,服务企业370多家。

该中心还拥有两个宣传知识产权知识的窗口:中国陶瓷知识产权信息网、中国知识产权远程教育平台。2012年,江西省科技厅认定中心为省级科技查新单位。中心拥有中国、美国、英国、德国、瑞士、俄罗斯多个国家与组织的专利数据库,为全国陶瓷行业及江西省企事业机构提供国内外专利的检索、咨询、专利转让与推广、专利统计与分析、专利专题数据库建设等服务。经过多年应用与实践,该中心建立并完善了现代专利信息服务模式,提出并逐步健全的全国陶瓷行业-全省新兴产业-地市重点产业-各地重点企业服务理念为行业所认可和肯定。

第三,特色发展服务平台——通过理论分析、问卷调査等,构建陶瓷文化知识产权服务平台评价指标体系,推进大学生陶瓷文化作品知识产权建设特色化。

转变陶瓷文化知识产权服务平台建设的观念,融入社会信息交流中突出自身特点和优势,进一步突出大学生陶瓷文化作品知识产权重要性,适应社会对陶瓷文化要求,旨在增强陶瓷文化的吸引力和影响力,实现陶瓷文化在社会中的理论和实践价值。

积极进行大学生陶瓷文化作品知识产权发展评价。随着新媒体技术和陶瓷文化事业的不断发展,新的传播理念、模式愈发冲击着传统陶瓷文化信息传播模式,更影响和改变着人们信息传播习惯和消费方式。通过适应新媒体信息传播环境,正视大学生陶瓷文化不断同质化趋势,凸显出文化特色,推进实现其社会价值。

认真实证分析主要服务平台的发展水平。研判陶瓷文化作品知识产权发展总体水平,整合现有的陶瓷文化作品知识产权网络资源,运用新媒体建设好陶瓷文化知识产权服务平台,完善本土化、符合国情、具有地方特色、文化传统的知识产权管理,逐步向商标服务、版权服务扩展,保护陶瓷文化知识产权合法权益。

3 创新点

根据大学生陶瓷文化知识产权服务平台的总体建设工作目标,运用新媒体进行大学生陶瓷文化作品知识产权保护,提升其在实物展陈和虚拟网络中信息传播和服务质量,促进陶瓷文化知识产权事业健康持续快速发展,走综合发展之有效路径。

通过提高陶瓷文化知识产权保护意识,加强陶瓷文化发明专利、实用新型专利、外观设计专利、版权、商标品牌等之间的优势互补,并在平台上加大宣传发挥出的预期效果,为陶瓷行业提供国内外专利导航、商标咨询和版权维权等各种服务,推进陶瓷行业技术创新与产业升级,发挥出知识产权在品牌建设中的积极作用。

参考文献:

[1]朱云莉,曾强,魏群.陶瓷名家作品在艺术授权经营中的知识产权保护问题研究[J].中国陶瓷,2016(3).

[2]吴汉东.知识产权领域的表达自由:保护与规制[J].社会科学文摘,2016(7).

4.流媒体服务器架构知识 篇四

一、微服务架构模式

1.1 模式描述 1.2 模式拓扑 1.3 避免依赖与调度 1.4 注意事项 1.5 模式分析 二、Android中的微服务架构 三、结语

前段时间我们翻译的《软件架构模式》( 完整书籍的地址 ) 对外发布之后得到了大家的一致好评,书中讲述了五种经典、流行的软件架构模式,同时分析了五种模式的实现、优缺点等,为我们的开发工作提供了很有价值的指导,但是《软件架构模式》的问题在于没有结合具体的示例来让这些理论知识更易于吸收,因此有些同学在我的开发群反馈: 书看起来是挺好的,但是没有具体的示例感觉看得迷迷糊糊的。因此在下打算写一些结合Android源码或者开发的文章来更深入的讲述这些架构模式,理论与实践相结合,让大家更深刻、更具体的学习到这些架构的魅力所在。

5.流媒体服务器架构知识 篇五

关键词:工具软件;知识架构分析与评估;智能化;个性化;控制系统模型;统计学;模糊算法

中图分类号:TP311.5文献标识码:A文章编号:1009-3044(2016)03-0083-02

本软件建立学习过程控制系统模型,并据此设计评估软件,设计思路新颖。现有教育软件,主要关注的是学习方法和学习资源,在学校学生管理方面,多是应用大数据库对整体分析。在分析知识架构方面,没有做成工具软件,也没有应用于每个学生。本软件将实现对学生的个性化智能评估。

1现有教育软件分析

随着经济与科技的发展,政府、家庭更加重视教育,现有教育系统的一些问题也日益显露[1]:

1)传统“大班教育”模式下,教师只能大致了解到班级整体学习情况和个别优秀学生的掌握状况,并不能照顾到每一名同学,从而导致了一些同学的学习积极性降低。

2)家长更愿意让孩子接受“小班教育”或“一对一教育”,该教育形式多按课时收费,成本远远高于学校的“大班教育”,很多家庭难以承担高额的辅导费用[1]。

3)中学学生管理系统多采用数理统计分析,只能分析出一些最基本数据及整体水平,并不能根据考试成绩分析出每一位学生的知识点掌握状况[2]。针对以上问题,为了充分发挥学生学习的主动性,高效、便捷的分析出学生的知识盲点,减少家庭高额的辅导费用,设计了中小学生知识架构分析与评估智能工具软件。该软件有如下优点:

1)该软件能高效、便捷地分析出每位学生的知识点掌握情况。相比学校学生管理系统,更加个性化,可满足家庭、学校的需求。

2)可与网络上教育软件嫁接。在教育软件上网上答题,提交后可自动分析学生知识点掌握情况。

3)有效减少家庭高额的辅导费用。

4)该工具软件成本很低、普及性强。

2软件设计

2.1学习过程控制系统模型的建立

中小学生知识架构分析与评估的智能工具软件主要针对中小学生知识点进行分析,下面将结合简化的教育模式结构图来详解本工具软件的实现过程。

2.1.1传统师生教育系统

当今教育方式主要为:

方式1:教师讲授知识——学生做题——测试成绩。此方式没有反馈,全靠学生的自觉性和能力,学习效率低。

方式2:教师讲授知识——学生做题——测试成绩——家长分析——反馈给家教。家教主要对学生的错题进行分析,但是错题并不能完全反映出学生知识盲点,也有一部分知识掌握不扎实,且家教与学生需要较长磨合期。

方式3:教师讲授知识——学生做题——测试成绩——教师分析——反馈给教师。教师主要对整体成绩分析,缺乏个性化,无法照顾到每位同学。

2.2.2中小学生知识架构分析与评估的智能软件

为解决上述问题,我们设计了中小学生知识架构分析与评估的智能软件。该软件通过对教育模式结构图功能、反馈的添加,让每一位学生都能享受个性化的知识评估,高效、便捷的分析出知识盲点,同时降低家庭教育费用,减少家教和学生的磨合时间。在基本的教育系统中,以评价软件为核心,极大的优化反馈效率。教师出题,学生做题后反馈给教师,教师批阅并将结果输入该软件,软件将自动整理信息,得出详细的学生知识点评估统计图,将结果反馈给所以学生,使所有学生能高效、了解自己知识盲点,更能方便家教因材施教。上述环节不只一次反馈,经过多次过程之后将不断缩小学生的不足之处,更快地促进学生学习。

2.2软件设计原理

2.2.1科学权衡

给予作业、测试、考试成绩不同的权重,软件可以由家长、教师、家教根据实际情况修改权重,增加软件对不同教学情况的适应性[3]。

2.2.2模糊算法

采用模糊算法对上一个步骤处理后的数据继续分析。引入模糊隶属公式,设置六个模糊语言变量:极优、优、良、中、差、极差[4]。模糊算法公式图:对于任意一个成绩,都与模糊隶属公式拥有两个交点值:u(x0),v(x0),选取较大的值作为结果,给出模糊语言变量的评价。

2.2.3周期性时间统计

学生对于知识点的掌握情况是随时间的改变而改变的,这就需要对数据进一步处理,根据时间次序给予数据不同权重[5]。分值G=a0x(i)+a1x(i+1)+……+amx(n)(m=n-i)满足:a0+a1+……am=1其中a0,a1,……,am为权重。2.3功能设计

2.3.1知识点数据库

1)教学大纲

系统内部含有一个完整的知识点数据库,按学科、章节细分知识点类型、知识点。

2)知识点录入系统

知识点录入分为两种实现形式,分别为人工录入和软件嫁接。人工录入由教师、家长等人将试卷每一道题的知识点通过大纲目录录入系统。可以很方便地找出题目对应的知识点,然后录入,录入结果填入程序内部表格;软件嫁接即该软件可与市面上自带题库的教育软件嫁接,省去人工录入,学生网上答题,提交后软件自动分析,能极大降低工作量。

2.3.2成绩录入

录入的成绩包括作业、测试、考试成绩,给予三种成绩不同的权重。成绩录入界面与知识库相对应,以试卷格式录入。同样此处也可嫁接软件直接评分。

2.3.3评估与统计

2.3.3.1评估

1)统计评估

统计数据,以知识点为主要关键字,统计每个知识点掌握百分比,分值型分值低于80%视为错误。

2)模糊算法评估

根据知识点的正确率分析,在此使用了基本的模糊算法加以解决。模糊算法将对上一个步骤处理后的数据继续进行分析。引入模糊隶属公式,设置六个模糊语言变量:极优、优、良、中、差、极差。计算方法:以每个学生为单位,对应每个知识点,都通过模糊算法给予学生评级。对应一个x值(0

2.3.3.2实时统计和周期性统计

1)实时统计

实时统计可以绘制知识点掌握情况评价图,并及时反馈给学生、家长、教师。

2)周期性统计

学生对于知识点的掌握情况是随时间的改变而改变,对数据进一步处理,根据时间次序给予数据不同权重。

2.3.4输出系统

输出即为软件反馈给教师学生的数据,在经过上述步骤处理后之后,得到许多个表。输出系统将以图表的形式反馈给教师与学生。输出内容为:1)一次测评后,给予每位学生知识点掌握情况统计情况表和柱状图,都以百分制的形式给出,知识盲点一目了然。

2)多次测评后,给予单一知识点多次测评曲线图,按时间顺序排列,随时能查看对于某一知识点掌握情况。

3)多次测评后,给予所有知识点掌握情况一览图,给出综合评价[6]。

3结束语

该软件可以达到充分发挥学生主动性,高效、便捷分析出知识盲点,提高学生的学习效率和教育质量,减少家庭教育费用。

参考文献:

6.百万用户级游戏服务器架构设计 篇六

服务器结构探讨--最简单的结构

所谓服务器结构,也就是如何将服务器各部分合理地安排,以实现最初的功能需求。所以,结构本无所谓正确与错误;当然,优秀的结构更有助于系统的搭建,对系统的可扩展性及可维护性也有更大的帮助。

好的结构不是一蹴而就的,而且每个设计者心中的那把尺都不相同,所以这个优秀结构的定义也就没有定论。在这里,我们不打算对现有游戏结构做评价,而是试着从头开始搭建一个我们需要的MMOG结构。

对于一个最简单的游戏服务器来说,它只需要能够接受来自客户端的连接请求,然后处理客户端在游戏世界中的移动及交互,也即游戏逻辑处理即可。如果我们把这两项功能集成到一个服务进程中,则最终的结构很简单:

client-----server

嗯,太简单了点,这样也敢叫服务器结构?好吧,现在我们来往里面稍稍加点东西,让它看起来更像是服务器结构一些。

一般来说,我们在接入游戏服务器的时候都会要提供一个帐号和密码,验证通过后才能进入。关于为什么要提供用户名和密码才能进入的问题我们这里不打算做过多讨论,云风曾对此也提出过类似的疑问,并给出了只用一个标识串就能进入的设想,有兴趣的可以去看看他们的讨论。但不管是采用何种方式进入,照目前看来我们的服务器起码得提供一个帐号验证的功能。

我们把观察点先集中在一个大区内。在大多数情况下,一个大区内都会有多组游戏服,也就是多个游戏世界可供选择。简单点来实现,我们完全可以抛弃这个大区的概念,认为一个大区也就是放在同一个机房的多台服务器组,各服务器组间没有什么关系。这样,我们可为每组服务器单独配备一台登录服。最后的结构图应该像这样:

loginServer

gameServer

|

/

|

/

client

该结构下的玩家操作流程为,先选择大区,再选择大区下的某台服务器,即某个游戏世界,点击进入后开始帐号验证过程,验证成功则进入了该游戏世界。但是,如果玩家想要切换游戏世界,他只能先退出当前游戏世界,然后进入新的游戏世界重新进行帐号验证。

早期的游戏大都采用的是这种结构,有些游戏在实现时采用了一些技术手段使得在切换游戏服时不需要再次验证帐号,但整体结构还是未做改变。

该结构存在一个服务器资源配置的问题。因为登录服处理的逻辑相对来说比较简单,就是将玩家提交的帐号和密码送到数据库进行验证,和生成会话密钥发送给游戏服和客户端,操作完成后连接就会立即断开,而且玩家在以后的游戏过程中不会再与登录服打任何交道。这样处理短连接的过程使得系统在大多数情况下都是比较空闲的,但是在某些时候,由于请求比较密集,比如开新服的时候,登录服的负载又会比较大,甚至会处理不过来。

另外在实际的游戏运营中,有些游戏世界很火爆,而有些游戏世界却非常冷清,甚至没有多少人玩的情况也是很常见的。所以,我们能否更合理地配置登录服资源,使得整个大区内的登录服可以共享就成了下一步改进的目标。

服务器结构探讨--登录服的负载均衡

回想一下我们在玩wow时的操作流程:运行wow.exe进入游戏后,首先就会要求我们输入用户名和密码进行验证,验证成功后才会出来游戏世界列表,之后是排队进入游戏世界,开始游戏...可以看到跟前面的描述有个很明显的不同,那就是要先验证帐号再选择游戏世界。这种结构也就使得登录服不是固定配备给个游戏世界,而是全区共有的。

我们可以试着从实际需求的角度来考虑一下这个问题。正如我们之前所描述过的那样,登录服在大多数情况下都是比较空闲的,也许我们的一个拥有20个游戏世界的大区仅仅使用10台或更少的登录服即可满足需求。而当在开新区的时候,或许要配备40台登录服才能应付那如潮水般涌入的玩家登录请求。所以,登录服在设计上应该能满足这种动态增删的需求,我们可以在任何时候为大区增加或减少登录服的部署。

当然,在这里也不会存在要求添加太多登录服的情况。还是拿开新区的情况来说,即使新增加登录服满足了玩家登录的请求,游戏世界服的承载能力依然有限,玩家一样只能在排队系统中等待,或者是进入到游戏世界中导致大家都卡。

另外,当我们在增加或移除登录服的时候不应该需要对游戏世界服有所改动,也不会要求重启世界服,当然也不应该要求客户端有什么更新或者修改,一切都是在背后自动完成。

最后,有关数据持久化的问题也在这里考虑一下。一般来说,使用现有的商业数据库系统比自己手工技术先进要明智得多。我们需要持久化的数据有玩家的帐号及密码,玩家创建的角色相关信息,另外还有一些游戏世界全局共有数据也需要持久化。

好了,需求已经提出来了,现在来考虑如何将其实现。

对于负载均衡来说,已有了成熟的解决方案。一般最常用,也最简单部署的应该是基于DNS的负载均衡系统了,其通过在DNS中为一个域名配置多个IP地址来实现。最新的DNS服务已实现了根据服务器系统状态来实现的动态负载均衡,也就是实现了真正意义上的负载均衡,这样也就有效地解决了当某台登录服当机后,DNS服务器不能立即做出反应的问题。当然,如果找不到这样的解决方案,自己从头打造一个也并不难。而且,通过DNS来实现的负载均衡已经包含了所做的修改对登录服及客户端的透明。

而对于数据库的应用,在这种结构下,登录服及游戏世界服都会需要连接数据库。从数据库服务器的部署上来说,可以将帐号和角色数据都放在一个中心数据库中,也可分为两个不同的库分别来处理,基到从物理上分到两台不同的服务器上去也行。

但是对于不同的游戏世界来说,其角色及游戏内数据都是互相独立的,所以一般情况下也就为每个游戏世界单独配备一台数据库服务器,以减轻数据库的压力。所以,整体的服务器结构应该是一个大区有一台帐号数据库服务器,所有的登录服都连接到这里。而每个游戏世界都有自己的游戏数据库服务器,只允许本游戏世界内的服务器连接。

最后,我们的服务器结构就像这样:

大区服务器

/

|

/

|

登录服1

登录服2

世界服1

世界服2

|

|

|

|

|

|

帐号数据库

DBS

DBS

这里既然讨论到了大区及帐号数据库,所以顺带也说一下关于激活大区的概念。wow中一共有八个大区,我们想要进入某个大区游戏之前,必须到官网上激活这个区,这是为什么呢?

一般来说,在各个大区帐号数据库之上还有一个总的帐号数据库,我们可以称它为中心数据库。比如我们在官网上注册了一个帐号,这时帐号数据是只保存在中心数据库上的。而当我们要到一区去创建角色开始游戏的时候,在一区的帐号数据库中并没有我们的帐号数据,所以,我们必须先到官网上做一次激活操作。这个激活的过程也就是从中心库上把我们的帐号数据拷贝到所要到的大区帐号数据库中。

服务器结构探讨--简单的世界服实现

讨论了这么久我们一直都还没有进入游戏世界服务器内部,现在就让我们来窥探一下里面的结构吧。

对于现在大多数MMORPG来说,游戏服务器要处理的基本逻辑有移动、聊天、技能、物品、任务和生物等,另外还有地图管理与消息广播来对其他高级功能做支撑。如纵队、好友、公会、战场和副本等,这些都是通过基本逻辑功能组合或扩展而成。

在所有这些基础逻辑中,与我们要讨论的服务器结构关系最紧密的当属地图管理方式。决定了地图的管理方式也就决定了我们的服务器结构,我们仍然先从最简单的实现方式开始说起。

回想一下我们曾战斗过无数个夜晚的暗黑破坏神,整个暗黑的世界被分为了若干个独立的小地图,当我们在地图间穿越时,一般都要经过一个叫做传送门的装置。世界中有些地图间虽然在地理上是直接相连的,但我们发现其游戏内部的逻辑却是完全隔离的。可以这样认为,一块地图就是一个独立的数据处理单元。

既然如此,我们就把每块地图都当作是一台独立的服务器,他提供了在这块地图上游戏时的所有逻辑功能,至于内部结构如何划分我们暂不理会,先把他当作一个黑盒子吧。

当两个人合作做一件事时,我们可以以对等的关系相互协商着来做,而且一般也都不会有什么问题。当人数增加到三个时,我们对等的合作关系可能会有些复杂,因为我们每个人都同时要与另两个人合作协商。正如俗语所说的那样,三个和尚可能会碰到没水喝的情况。当人数继续增加,情况就变得不那么简单了,我们得需要一个管理者来对我们的工作进行分工、协调。游戏的地图服务器之间也是这么回事。

一般来说,我们的游戏世界不可能会只有一块或者两块小地图,那顺理成章的,也就需要一个地图管理者。先称它为游戏世界的中心服务器吧,毕竟是管理者嘛,大家都以它为中心。

中心服务器主要维护一张地图ID到地图服务器地址的映射表。当我们要进入某张地图时,会从中心服上取得该地图的IP和port告诉客户端,客户端主动去连接,这样进入他想要去的游戏地图。在整个游戏过程中,客户端始终只会与一台地图服务器保持连接,当要切换地图的时候,在获取到新地图的地址后,会先与当前地图断开连接,再进入新的地图,这样保证玩家数据在服务器上只有一份。

我们来看看结构图是怎样的:

中心服务器

/ / 登录服 地图1 地图2 地图n | / / | / /

客户端

很简单,不是吗。但是简单并不表示功能上会有什么损失,简单也更不能表示游戏不能赚钱。早期不少游戏也确实采用的就是这种简单结构。

服务器结构探讨--继续世界服

都已经看出来了,这种每切换一次地图就要重新连接服务器的方式实在是不够优雅,而且在实际游戏运营中也发现,地图切换导致的卡号,复制装备等问题非常多,这里完全就是一个事故多发地段,如何避免这种频繁的连接操作呢?

最直接的方法就是把那个图倒转过来就行了。客户端只需要连接到中心服上,所有到地图服务器的数据都由中心服来转发。很完美的解决方案,不是吗?

这种结构在实际的部署中也遇到了一些挑战。对于一般的MMORPG服务器来说,单台服务器的承载量平均在2000左右,如果你的服务器很不幸地只能带1000人,没关系,不少游戏都是如此;如果你的服务器上跑了3000多玩家依然比较流畅,那你可以自豪地告诉你的策划,多设计些大量消耗服务器资源的玩法吧,比如大型国战、公会战争等。

2000人,似乎我们的策划朋友们不大愿意接受这个数字。我们将地图服务器分开来原来也是想将负载分开,以多带些客户端,现在要所有的连接都从中心服上转发,那连接数又遇到单台服务器的可最大承载量的瓶颈了。

这里有必要再解释下这个数字。我知道,有人一定会说,才带2000人,那是你水平不行,我随便写个TCP服务器都可带个五六千连接。问题恰恰在于你是随便写的,而MMORPG的服务器是复杂设计的。如果一个演示socket API用的echo服务器就能满足MMOG服务器的需求,那写服务器该是件多么惬意的事啊。

但我们所遇到的事实是,服务器收到一个移动包后,要向周围所有人广播,而不是echo服务器那样简单的回应;服务器在收到一个连接断开通知时要向很多人通知玩家退出事件,并将该玩家的资料写入数据库,而不是echo服务器那样什么都不需要做;服务器在收到一个物品使用请求包后要做一系列的逻辑判断以检查玩家有没有作弊;服务器上还启动着很多定时器用来更新游戏世界的各种状态......其实这么一比较,我们也看出资源消耗的所在了:服务器上大量的复杂的逻辑处理。再回过头来看看我们想要实现的结构,我们既想要有一个唯一的入口,使得客户端不用频繁改变连接,又希望这个唯一入口的负载不会太大,以致于接受不了多少连接。

仔细看一看这个需求,我们想要的仅仅只是一台管理连接的服务器,并不打算让他承担太多的游戏逻辑。既然如此,那五六千个连接也还有满足我们的要求。至少在现在来说,一个游戏世界内,也就是一组服务器内同时有五六千个在线的玩家还是件让人很兴奋的事。事实上,在大多数游戏的大部分时间里,这个数字也是很让人眼红的。

什么?你说梦幻、魔兽还有史先生的那个什么征途远不止这么点人了!噢,我说的是大多数,是大多数,不包括那些明星。你知道大陆现在有多少游戏在运营吗?或许你又该说,我们不该在一开始就把自己的目标定的太低!好吧,我们还是先不谈这个。

继续我们的结构讨论。一般来说,我们把这台负责连接管理的服务器称为网关服务器,因为内部的数据都要通过这个网关才能出去,不过从这台服务器提供的功能来看,称其为反向代理服务器可能更合适。我们也不在这个名字上纠缠了,就按大家通用的叫法,还是称他为网关服务器吧。

网关之后的结构我们依然可以采用之前描述的方案,只是,似乎并没有必要为每一个地图都开一个独立的监听端口了。我们可以试着对地图进行一些划分,由一个Master Server来管理一些更小的Zone Server,玩家通过网关连接到Master Server上,而实际与地图有关的逻辑是分派给更小的Zone Server去处理。

最后的结构看起来大概是这样的:

Zone Server Zone Server / / Master Server Master Server / / / / Gateway Server / | / | / | Center Server | | Client

服务器结构探讨--最终的结构

如果我们就此打住,可能马上就会有人要嗤之以鼻了,就这点古董级的技术也敢出来现。好吧,我们还是把之前留下的问题拿出来解决掉吧。

一般来说,当某一部分能力达不到我们的要求时,最简单的解决方法就是在此多投入一点资源。既然想要更多的连接数,那就再加一台网关服务器吧。新增加了网关服后需要在大区服上做相应的支持,或者再简单点,有一台主要的网关服,当其负载较高时,主动将新到达的连接重定向到其他网关服上。

而对于游戏服来说,有一台还是多台网关服是没有什么区别的。每个代表客户端玩家的对象内部都保留一个代表其连接的对象,消息广播时要求每个玩家对象使用自己的连接对象发送数据即可,至于连接是在什么地方,那是完全透明的。当然,这只是一种简单的实现,也是普通使用的一种方案,如果后期想对消息广播做一些优化的话,那可能才需要多考虑一下。

既然说到了优化,我们也稍稍考虑一下现在结构下可能采用的优化方案。

首先是当前的Zone Server要做的事情太多了,以至于他都处理不了多少连接。这其中最消耗系统资源的当属生物的AI处理了,尤其是那些复杂的寻路算法,所以我们可以考虑把这部分AI逻辑独立出来,由一台单独的AI服务器来承担。

然后,我们可以试着把一些与地图数据无关的公共逻辑放到Master Server上去实现,这样Zone Server上只保留了与地图数据紧密相关的逻辑,如生物管理,玩家移动和状态更新等。

还有聊天处理逻辑,这部分与游戏逻辑没有任何关联,我们也完全可以将其独立出来,放到一台单独的聊天服务器上去实现。

最后是数据库了,为了减轻数据库的压力,提高数据请求的响应速度,我们可以在数据库之前建立一个数据库缓存服务器,将一些常用数据缓存在此,服务器与数据库的通信都要通过这台服务器进行代理。缓存的数据会定时的写入到后台数据库中。

好了,做完这些优化我们的服务器结构大体也就定的差不多了,暂且也不再继续深入,更细化的内容等到各个部分实现的时候再探讨。

好比我们去看一场晚会,舞台上演员们按着预定的节目单有序地上演着,但这就是整场晚会的全部吗?显然不止,在幕后还有太多太多的人在忙碌着,甚至在晚会前和晚会后都有。我们的游戏服务器也如此。

在之前描述的部分就如同舞台上的演员,是我们能直接看到的,幕后的工作人员我们也来认识一下。

现实中有警察来维护秩序,游戏中也如此,这就是我们常说的GM。GM可以采用跟普通玩家一样的拉入方式来进入游戏,当然权限会比普通玩家高一些,也可以提供一台GM服务器专门用来处理GM命令,这样可以有更高的安全性,GM服一般接在中心服务器上。

在以时间收费的游戏中,我们还需要一台计费的服务器,这台服务器一般接在网关服务器上,注册玩家登录和退出事件以记录玩家的游戏时间。

任何为用户提供服务的地方都会有日志记录,游戏服务器当然也不例外。从记录玩家登录的时间,地址,机器信息到游戏过程中的每一项操作都可以作为日志记录下来,以备查错及数据挖掘用。至于搜集玩家机器资料所涉及到的法律问题不是我们该考虑的。

差不多就这么多了吧,接下来我们会按照这个大致的结构来详细讨论各部分的实现。

服务器结构探讨--一点杂谈

再强调一下,服务器结构本无所谓好坏,只有是否适合自己。我们在前面探讨了一些在现在的游戏中见到过的结构,并尽我所知地分析了各自存在的一些问题和可以做的一些改进,希望其中没有谬误,如果能给大家也带来些启发那自然更好。

突然发现自己一旦罗嗦起来还真是没完没了。接下来先说说我在开发中遇到过的一些困惑和一基础问题探讨吧,这些问题可能有人与我一样,也曾遇到过,或者正在被困扰中,而所要探讨的这些基础问题向来也是争论比较多的,我们也不评价其中的好与坏,只做简单的描述。

首先是服务器操作系统,linux与windows之争随处可见,其实在大多数情况下这不是我们所能决定的,似乎各大公司也基本都有了自己的传统,如网易的freebsd,腾讯的linux等。如果真有权利去选择的话,选自己最熟悉的吧。

决定了OS也就基本上确定了网络IO模型,windows上的IOCP和linux下的epool,或者直接使用现有的网络框架,如ACE和asio等,其他还有些商业的网络库在国内的使用好像没有见到,不符合中国国情嘛。:)

然后是网络协议的选择,以前的选择大多倾向于UDP,为了可靠传输一般自己都会在上面实现一层封装,而现在更普通的是直接采用本身就很可靠的TCP,或者TCP与UDP的混用。早期选择UDP的主要原因还是带宽限制,现在宽带普通的情况下TCP比UDP多出来的一点点开销与开发的便利性相比已经不算什么了。当然,如果已有了成熟的可靠UDP库,那也可以继续使用着。

还有消息包格式的定义,这个曾在云风的blog上展开过激烈的争论。消息包格式定义包括三段,包长、消息码和包体,争论的焦点在于应该是消息码在前还是包长在前,我们也把这个当作是信仰问题吧,有兴趣的去云风的blog上看看,论论。

另外早期有些游戏的包格式定义是以特殊字符作分隔的,这样一个好处是其中某个包出现错误后我们的游戏还能继续。但实际上,我觉得这是完全没有必要的,真要出现这样的错误,直接断开这个客户端的连接可能更安全。而且,以特殊字符做分隔的消息包定义还加大了一点点网络数据量。

最后是一个纯技术问题,有关socket连接数的最大限制。开始学习网络编程的时候我犯过这样的错误,以为port的定义为unsigned short,所以想当然的认为服务器的最大连接数为65535,这会是一个硬性的限制。而实际上,一个socket描述符在windows上的定义是unsigned int,因此要有限制那也是四十多亿,放心好了。

在服务器上port是监听用的,想象这样一种情况,web server在80端口上监听,当一个连接到来时,系统会为这个连接分配一个socket句柄,同时与其在80端口上进行通讯;当另一个连接到来时,服务器仍然在80端口与之通信,只是分配的socket句柄不一样。这个socket句柄才是描述每个连接的唯一标识。按windows网络编程第二版上的说法,这个上限值配置影响。

好了,废话说完了,下一篇,我们开始进入登录服的设计吧。

登录服的设计--功能需求

正如我们在前面曾讨论过的,登录服要实现的功能相当简单,就是帐号验证。为了便于描述,我们暂不引入那些讨论过的优化手段,先以最简单的方式实现,另外也将基本以mangos的代码作为参考来进行描述。

想象一下帐号验证的实现方法,最容易的那就是把用户输入的明文用帐号和密码直接发给登录服,服务器根据帐号从数据库中取出密码,与用户输入的密码相比较。

这个方法存在的安全隐患实在太大,明文的密码传输太容易被截获了。那我们试着在传输之前先加一下密,为了服务器能进行密码比较,我们应该采用一个可逆的加密算法,在服务器端把这个加密后的字串还原为原始的明文密码,然后与数据库密码进行比较。既然是一个可逆的过程,那外挂制作者总有办法知道我们的加密过程,所以,这个方法仍不够安全。

哦,如果我们只是希望密码不可能被还原出来,那还不容易吗,使用一个不可逆的散列算法就行了。用户在登录时发送给服务器的是明文的帐号和经散列后的不可逆密码串,服务器取出密码后也用同样的算法进行散列后再进行比较。比如,我们就用使用最广泛的md5算法吧。噢,不要管那个王小云的什么论文,如果我真有那么好的运气,早中500w了,还用在这考虑该死的服务器设计吗?

似乎是一个很完美的方案,外挂制作者再也偷不到我们的密码了。慢着,外挂偷密码的目的是什么?是为了能用我们的帐号进游戏!如果我们总是用一种固定的算法来对密码做散列,那外挂只需要记住这个散列后的字串就行了,用这个做密码就可以成功登录。

嗯,这个问题好解决,我们不要用固定的算法进行散列就是了。只是,问题在于服务器与客户端采用的散列算法得出的字串必须是相同的,或者是可验证其是否匹配的。很幸运的是,伟大的数学字们早就为我们准备好了很多优秀的这类算法,而且经理论和实践都证明他们也确实是足够安全的。

这其中之一是一个叫做SRP的算法,全称叫做Secure Remote Password,即安全远程密码。wow使用的是第6版,也就是SRP6算法。有关其中的数学证明,如果有人能向我解释清楚,并能让我真正弄明白的话,我将非常感激。不过其代码实现步骤倒是并不复杂,mangos中的代码也还算清晰,我们也不再赘述。

登录服除了帐号验证外还得提供另一项功能,就是在玩家的帐号验证成功后返回给他一个服务器列表让他去选择。这个列表的状态要定时刷新,可能有新的游戏世界开放了,也可能有些游戏世界非常不幸地停止运转了,这些状态的变化都要尽可能及时地让玩家知道。不管发生了什么事,用户都有权利知道,特别是对于付过费的用户来说,我们不该藏着掖着,不是吗?

这个游戏世界列表的功能将由大区服来提供,具体的结构我们在之前也描述过,这里暂不做讨论。登录服将从大区服上获取到的游戏世界列表发给已验证通过的客户端即可。好了,登录服要实现的功能就这些,很简单,是吧。

确实是太简单了,不过简单的结构正好更适合我们来看一看游戏服务器内部的模块结构,以及一些服务器共有组件的实现方法。这就留作下一篇吧。

服务器公共组件实现--mangos的游戏主循环

当阅读一项工程的源码时,我们大概会选择从main函数开始,而当开始一项新的工程时,第一个写下的函数大多也是main。那我们就先来看看,游戏服务器代码实现中,main函数都做了些什么。

由于我在读技术文章时最不喜看到的就是大段大段的代码,特别是那些直接Ctrl+C再Ctrl+V后未做任何修改的代码,用句时髦的话说,一点技术含量都没有!所以在我们今后所要讨论的内容中,尽量会避免出现直接的代码,在有些地方确实需要代码来表述时,也将会选择使用伪码。

先从mangos的登录服代码开始。mangos的登录服是一个单线程的结构,虽然在数据库连接中可以开启一个独立的线程,但这个线程也只是对无返回结果的执行类SQL做缓冲,而对需要有返回结果的查询类SQL还是在主逻辑线程中阻塞调用的。

登录服中唯一的这一个线程,也就是主循环线程对监听的socket做select操作,为每个连接进来的客户端读取其上的数据并立即进行处理,直到服务器收到SIGABRT或SIGBREAK信号时结束。

所以,mangos登录服主循环的逻辑,也包括后面游戏服的逻辑,主循环的关键代码其实是在SocketHandler中,也就是那个Select函数中。检查所有的连接,对新到来的连接调用OnAccept方法,有数据到来的连接则调用OnRead方法,然后socket处理器自己定义对接收到的数据如何处理。

很简单的结构,也比较容易理解。

只是,在对性能要求比较高的服务器上,select一般不会是最好的选择。如果我们使用windows平台,那IOCP将是首选;如果是linux,epool将是不二选择。我们也不打算讨论基于IOCP或是基于epool的服务器实现,如果仅仅只是要实现服务器功能,很简单的几个API调用即可,而且网上已有很多好的教程;如果是要做一个成熟的网络服务器产品,不是我几篇简单的技术介绍文章所能达到。

另外,在服务器实现上,网络IO与逻辑处理一般会放在不同的线程中,以免耗时较长的IO过程阻塞住了需要立即反应的游戏逻辑。

数据库的处理也类似,会使用异步的方式,也是避免耗时的查询过程将游戏服务器主循环阻塞住。想象一下,因某个玩家上线而发起的一次数据库查询操作导致服务器内所有在线玩家都卡住不动将是多么恐怖的一件事!

另外还有一些如事件、脚本、消息队列、状态机、日志和异常处理等公共组件,我们也会在接下来的时间里进行探讨。

服务器公共组件实现--继续来说主循环

前面我们只简单了解了下mangos登录服的程序结构,也发现了一些不足之处,现在我们就来看看如何提供一个更好的方案。

正如我们曾讨论过的,为了游戏主逻辑循环的流畅运行,所有比较耗时的IO操作都会分享到单独的线程中去做,如网络IO,数据库IO和日志IO等。当然,也有把这些分享到单独的进程中去做的。

另外对于大多数服务器程序来说,在运行时都是作为精灵进程或服务进程的,所以我们并不需要服务器能够处理控制台用户输入,我们所要处理的数据来源都来自网络。

这样,主逻辑循环所要做的就是不停要取消息包来处理,当然这些消息包不仅有来自客户端的玩家操作数据包,也有来自GM服务器的管理命令,还包括来自数据库查询线程的返回结果消息包。这个循环将一直持续,直到收到一个通知服务器关闭的消息包。

主逻辑循环的结构还是很简单的,复杂的部分都在如何处理这些消息包的逻辑上。我们可以用一段简单的伪码来描述这个循环过程:

while(Message* msg = getMessage())

{

if(msg为服务器关闭消息)

break;

处理msg消息;

}

这里就有一个问题需要探讨了,在getMessage()的时候,我们应该去哪里取消息?前面我们考虑过,至少会有三个消息来源,而我们还讨论过,这些消息源的IO操作都是在独立的线程中进行的,我们这里的主线程不应该直接去那几处消息源进行阻塞式的IO操作。

很简单,让那些独立的IO线程在接收完数据后自己送过来就是了。好比是,我这里提供了一个仓库,有很多的供货商,他们有货要给我的时候只需要交到仓库,然后我再到仓库去取就是了,这个仓库也就是消息队列。消息队列是一个普通的队列实现,当然必须要提供多线程互斥访问的安全性支持,其基本的接口定义大概类似这样:

IMessageQueue

{

void putMessage(Message*);

Message* getMessage();

}

网络IO,数据库IO线程把整理好的消息包都加入到主逻辑循环线程的这个消息队列中便返回。有关消息队列的实现和线程间消息的传递在ACE中有比较完全的代码实现及描述,还有一些使用示例,是个很好的参考。

这样的话,我们的主循环就很清晰了,从主线程的消息队列中取消息,处理消息,再取下一条消息......服务器公共组件实现--消息队列

既然说到了消息队列,那我们继续来稍微多聊一点吧。

我们所能想到的最简单的消息队列可能就是使用stl的list来实现了,即消息队列内部维护一个list和一个互斥锁,putMessage时将message加入到队列尾,getMessage时从队列头取一个message返回,同时在getMessage和putMessage之前都要求先获取锁资源。

实现虽然简单,但功能是绝对满足需求的,只是性能上可能稍稍有些不尽如人意。其最大的问题在频繁的锁竞争上。

对于如何减少锁竞争次数的优化方案,Ghost Cheng提出了一种。提供一个队列容器,里面有多个队列,每个队列都可固定存放一定数量的消息。网络IO线程要给逻辑线程投递消息时,会从队列容器中取一个空队列来使用,直到将该队列填满后再放回容器中换另一个空队列。而逻辑线程取消息时是从队列容器中取一个有消息的队列来读取,处理完后清空队列再放回到容器中。

这样便使得只有在对队列容器进行操作时才需要加锁,而IO线程和逻辑线程在操作自己当前使用的队列时都不需要加锁,所以锁竞争的机会大大减少了。

这里为每个队列设了个最大消息数,看来好像是打算只有当IO线程写满队列时才会将其放回到容器中换另一个队列。那这样有时也会出现IO线程未写满一个队列,而逻辑线程又没有数据可处理的情况,特别是当数据量很少时可能会很容易出现。Ghost Cheng在他的描述中没有讲到如何解决这种问题,但我们可以先来看看另一个方案。

这个方案与上一个方案基本类似,只是不再提供队列容器,因为在这个方案中只使用了两个队列,arthur在他的一封邮件中描述了这个方案的实现及部分代码。两个队列,一个给逻辑线程读,一个给IO线程用来写,当逻辑线程读完队列后会将自己的队列与IO线程的队列相调换。所以,这种方案下加锁的次数会比较多一些,IO线程每次写队列时都要加锁,逻辑线程在调换队列时也需要加锁,但逻辑线程在读队列时是不需要加锁的。

虽然看起来锁的调用次数是比前一种方案要多很多,但实际上大部分锁调用都是不会引起阻塞的,只有在逻辑线程调换队列的那一瞬间可能会使得某个线程阻塞一下。另外对于锁调用过程本身来说,其开销是完全可以忽略的,我们所不能忍受的仅仅是因为锁调用而引起的阻塞而已。

两种方案都是很优秀的优化方案,但也都是有其适用范围的。Ghost Cheng的方案因为提供了多个队列,可以使得多个IO线程可以总工程师的,互不干扰的使用自己的队列,只是还有一个遗留问题我们还不了解其解决方法。arthur的方案很好的解决了上一个方案遗留的问题,但因为只有一个写队列,所以当想要提供多个IO线程时,线程间互斥地写入数据可能会增大竞争的机会,当然,如果只有一个IO线程那将是非常完美的。

服务器公共组件实现--环形缓冲区

消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了。频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行。也许我们可以使用内存池,比如SGI STL中附带的小内存分配器。但是对于这种按照严格的先进先出顺序处理的,块大小并不算小的,而且块大小也并不统一的内存分配情况来说,更多使用的是一种叫做环形缓冲区的方案,mangos的网络代码中也有这么一个东西,其原理也是比较简单的。

就好比两个人围着一张圆形的桌子在追逐,跑的人被网络IO线程所控制,当写入数据时,这个人就往前跑;追的人就是逻辑线程,会一直往前追直到追上跑的人。如果追上了怎么办?那就是没有数据可读了,先等会儿呗,等跑的人向前跑几步了再追,总不能让游戏没得玩了吧。那要是追的人跑的太慢,跑的人转了一圈过来反追上追的人了呢?那您也先歇会儿吧。要是一直这么反着追,估计您就只能换一个跑的更快的追逐者了,要不这游戏还真没法玩下去。

前面我们特别强调了,按照严格的先进先出顺序进行处理,这是环形缓冲区的使用必须遵守的一项要求。也就是,大家都得遵守规定,追的人不能从桌子上跨过去,跑的人当然也不允许反过来跑。至于为什么,不需要多做解释了吧。

环形缓冲区是一项很好的技术,不用频繁的分配内存,而且在大多数情况下,内存的反复使用也使得我们能用更少的内存块做更多的事。

在网络IO线程中,我们会为每一个连接都准备一个环形缓冲区,用于临时存放接收到的数据,以应付半包及粘包的情况。在解包及解密完成后,我们会将这个数据包复制到逻辑线程消息队列中,如果我们只使用一个队列,那这里也将会是个环形缓冲区,IO线程往里写,逻辑线程在后面读,互相追逐。可要是我们使用了前面介绍的优化方案后,可能这里便不再需要环形缓冲区了,至少我们并不再需要他们是环形的了。因为我们对同一个队列不再会出现同时读和写的情况,每个队列在写满后交给逻辑线程去读,逻辑线程读完后清空队列再交给IO线程去写,一段固定大小的缓冲区即可。没关系,这么好的技术,在别的地方一定也会用到的。

服务器公共组件实现--发包的方式

前面一直都在说接收数据时的处理方法,我们应该用专门的IO线程,接收到完整的消息包后加入到主线程的消息队列,但是主线程如何发送数据还没有探讨过。

一般来说最直接的方法就是逻辑线程什么时候想发数据了就直接调用相关的socket API发送,这要求服务器的玩家对象中保存其连接的socket句柄。但是直接send调用有时候有会存在一些问题,比如遇到系统的发送缓冲区满而阻塞住的情况,或者只发送了一部分数据的情况也时有发生。我们可以将要发送的数据先缓存一下,这样遇到未发送完的,在逻辑线程的下一次处理时可以接着再发送。

考虑数据缓存的话,那这里这可以有两种实现方式了,一是为每个玩家准备一个缓冲区,另外就是只有一个全局的缓冲区,要发送的数据加入到全局缓冲区的时候同时要指明这个数据是发到哪个socket的。如果使用全局缓冲区的话,那我们可以再进一步,使用一个独立的线程来处理数据发送,类似于逻辑线程对数据的处理方式,这个独立发送线程也维护一个消息队列,逻辑线程要发数据时也只是把数据加入到这个队列中,发送线程循环取包来执行send调用,这时的阻塞也就不会对逻辑线程有任何影响了。

采用第二种方式还可以附带一个优化方案。一般对于广播消息而言,发送给周围玩家的数据都是完全相同的,我们如果采用给每个玩家一个缓冲队列的方式,这个数据包将需要拷贝多份,而采用一个全局发送队列时,我们只需要把这个消息入队一次,同时指明该消息包是要发送给哪些socket的即可。有关该优化的说明在云风描述其连接服务器实现的blog文章中也有讲到,有兴趣的可以去阅读一下。

服务器公共组件实现--状态机

有关State模式的设计意图及实现就不从设计模式中摘抄了,我们只来看看游戏服务器编程中如何使用State设计模式。

首先还是从mangos的代码开始看起,我们注意到登录服在处理客户端发来的消息时用到了这样一个结构体:

struct AuthHandler

{

eAuthCmd cmd;

uint32 status;

bool(AuthSocket::*handler)(void);

};

该结构体定义了每个消息码的处理函数及需要的状态标识,只有当前状态满足要求时才会调用指定的处理函数,否则这个消息码的出现是不合法的。这个status状态标识的定义是一个宏,有两种有效的标识,STATUS_CONNECTED和STATUS_AUTHED,也就是未认证通过和已认证通过。而这个状态标识的改变是在运行时进行的,确切的说是在收到某个消息并正确处理完后改变的。

我们再来看看设计模式中对State模式的说明,其中关于State模式适用情况里有一条,当操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态,这个状态通常用一个或多个枚举变量表示。

描述的情况与我们这里所要处理的情况是如此的相似,也许我们可以试一试。那再看看State模式提供的解决方案是怎样的,State模式将每一个条件分支放入一个独立的类中。

由于这里的两个状态标识只区分出了两种状态,所以,我们仅需要两个独立的类,用以表示两种状态即可。然后,按照State模式的描述,我们还需要一个Context类,也就是状态机管理类,用以管理当前的状态类。稍作整理,大概的代码会类似这样:

状态基类接口:

StateBase

{

void Enter()= 0;

void Leave()= 0;

void Process(Message* msg)= 0;

};

状态机基类接口:

MachineBase

{

void ChangeState(StateBase* state)= 0;

StateBase* m_curState;

};

我们的逻辑处理类会从MachineBase派生,当取出数据包后交给当前状态处理,前面描述的两个状态类从StateBase派生,每个状态类只处理该状态标识下需要处理的消息。当要进行状态转换时,调用MachineBase的ChangeState()方法,显示地告诉状态机管理类自己要转到哪一个状态。所以,状态类内部需要保存状态机管理类的指针,这个可以在状态类初始化时传入。具体的实现细节就不做过多描述了。

使用状态机虽然避免了复杂的判断语句,但也引入了新的麻烦。当我们在进行状态转换时,可能会需要将一些现场数据从老状态对象转移到新状态对象,这需要在定义接口时做一下考虑。如果不希望执行拷贝,那么这里公有的现场数据也可放到状态机类中,只是这样在使用时可能就不那么优雅了。<

BR>

正如同在设计模式中所描述的,所有的模式都是已有问题的另一种解决方案,也就是说这并不是唯一的解决方案。放到我们今天讨论的State模式中,就拿登录服所处理的两个状态来说,也许用mangos所采用的遍历处理函数的方法可能更简单,但当系统中的状态数量增多,状态标识也变多的时候,State模式就显得尤其重要了。

比如在游戏服务器上玩家的状态管理,还有在实现NPC人工智能时的各种状态管理,这些就留作以后的专题吧。

服务器公共组件--事件与信号

关于这一节,这几天已经打了好几遍草稿,总觉得说不清楚,也不好组织这些内容,但是打铁要趁热,为避免热情消退,先整理一点东西放这,好继续下面的主题,以后如果有机会再回来完善吧。本节内容欠考虑,希望大家多给点意见。

有些类似于QT中的event与signal,我将一些动作请求消息定义为事件,而将状态改变消息定义为信号。比如在QT应用程序中,用户的一次鼠标点击会产生一个鼠标点击事件加入到事件队列中,当处理此事件时可能会导致某个按钮控件产生一个clicked()信号。

对应到我们的服务器上的一个例子,玩家登录时会发给服务器一个请求登录的数据包,服务器可将其当作一个用户登录事件,该事件处理完后可能会产生一个用户已登录信号。

这样,与QT类似,对于事件我们可以重定义其处理方法,甚至过滤掉某些事件使其不被处理,但对于信号我们只是收到了一个通知,有些类似于Observe模式中的观察者,当收到更新通知时,我们只能更新自己的状态,对刚刚发生的事件我不已不能做任何影响。仔细来看,事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。

简单点说,就是我们可以为事件定义过滤器,使得事件可以被过滤。这一功能需求在游戏服务器上是到处存在的。

关于事件和信号机制的实现,网络上的开源训也比较多,比如FastDelegate,sigslot,boost::signal等,其中sigslot还被Google采用,在libjingle的代码中我们可以看到他是如何被使用的。

在实现事件和信号机制时或许可以考虑用同一套实现,在前面我们就分析过,两者唯一的区别仅在于返回值的处理上。

另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指明槽的位置。

在我们的需求中,因为没有窗口的概念,事件的处理也与信号类似,对注册过的处理器要按某个顺序依次回调,所以优先级的设置功能是需要的。

最后需要我们考虑的是事件和信号的处理方式。在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后,QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。我们需要注意的一个很重要的问题是会不会引起循环调用。

关于事件机制的考虑其实还很多,但都是一些不成熟的想法。在上面的文字中就同时出现了消息、事件和信号三个相近的概念,而在实际处理中,经常发现三者不知道如何界定的情况,实际的情况比我在这里描述的要混乱的多。

这里也就当是挖下一个坑,希望能够有所交流。

再谈登录服的实现

离我们的登录服实现已经太远了,先拉回来一下。

关于登录服、大区服及游戏世界服的结构之前已做过探讨,这里再把各自的职责和关系列一下。

GateWay/WorldServer GateWay/WodlServer LoginServer LoginServer DNSServer WorldServerMgr | | | | | | | | internet | clients

其中DNSServer负责带负载均衡的域名解析服务,返回LoginServer的IP地址给客户端。WorldServerMgr维护当前大区内的世界服列表,LoginServer会从这里取世界列表发给客户端。LoginServer处理玩家的登录及世界服选择请求。GateWay/WorldServer为各个独立的世界服或者通过网关连接到后面的世界服。

在mangos的代码中,我们注意到登录服是从数据库中取的世界列表,而在wow官方服务器中,我们却会注意到,这个世界服列表并不是一开始就固定,而是动态生成的。当每周一次的维护完成之后,我们可以很明显的看到这个列表生成的过程。刚开始时,世界列表是空的,慢慢的,世界服会一个个加入进来,而这里如果有世界服当机,他会显示为离线,不会从列表中删除。但是当下一次服务器再维护后,所有的世界服都不存在了,全部重新开始添加。

从上面的过程描述中,我们很容易想到利用一个临时的列表来保存世界服信息,这也是我们增加WorldServerMgr服务器的目的所在。GateWay/WorldServer在启动时会自动向WorldServerMgr注册自己,这样就把自己所代表的游戏世界添加到世界列表中了。类似的,如果DNSServer也可以让LoginServer自己去注册,这样在临时LoginServer时就不需要去改动DNSServer的配置文件了。

WorldServerMgr内部的实现很简单,监听一个固定的端口,接受来自WorldServer的主动连接,并检测其状态。这里可以用一个心跳包来实现其状态的检测,如果WorldServer的连接断开或者在规定时间内未收到心跳包,则将其状态更新为离线。另外WorldServerMgr还处理来自LoginServer的列表请求。由于世界列表并不常变化,所以LoginServer没有必要每次发送世界列表时都到WorldServerMgr上去取,LoginServer完全可以自己维护一个列表,当WorldServerMgr上的列表发生变化时,WorldServerMgr会主动通知所有的LoginServer也更新一下自己的列表。这个或许就可以用前面描述过的事件方式,或者就是观察者模式了。

WorldServerMgr实现所要考虑的内容就这些,我们再来看看LoginServer,这才是我们今天要重点讨论的对象。前面探讨一些服务器公共组件,那我们这里也应该试用一下,不能只是停留在理论上。先从状态机开始,前面也说过了,登录服上的连接会有两种状态,一是帐号密码验证状态,一是服务器列表选择状态,其实还有另外一个状态我们未曾讨论过,因为它与我们的登录过程并无多大关系,这就是升级包发送状态。三个状态的转换流程大致为:

LogonState--验证成功--版本检查--版本低于最新值--转到UpdateState |--版本等于最新值--转到WorldState

这个版本检查的和决定下一个状态的过程是在LogonState中进行的,下一个状态的选择是由当前状态来决定。密码验证的过程使用了SRP6协议,具体过程就不多做描述,每个游戏使用的方式也都不大一样。而版本检查的过程就更无值得探讨的东西,一个if-else即可。

升级状态其实就是文件传输过程,文件发送完毕后通知客户端开始执行升级文件并关闭连接。世界选择状态则提供了一个列表给客户端,其中包括了所有游戏世界网关服务器的IP、PORT和当前负载情况。如果客户端一直连接着,则该状态会以每5秒一次的频率不停刷新列表给客户端,当然是否值得这样做还是有待商榷。

整个过程似乎都没有值得探讨的内容,但是,还没有完。当客户端选择了一个世界之后该怎么办?wow的做法是,当客户端选择一个游戏世界时,客户端

会主动去连接该世界服的IP和PORT,然后进入这个游戏世界。与此同时,与登录服的连接还没有断开,直到客户端确实连接上了选定的世界服并且走完了排队过程为止。这是一个很必要的设计,保证了我们在因意外情况连接不上世界服或者发现世界服正在排队而想换另外一个试试时不会需要重新进行密码验证。

但是我们所要关注的还不是这些,而是客户端去连接游戏世界的网关服时服务器该如何识别我们。打个比方,有个不自觉的玩家不遵守游戏规则,没有去验证帐号密码就直接跑去连接世界服了,就如同一个不自觉的乘客没有换登机牌就直接跑到登机口一样。这时,乘务员会客气地告诉你要先换登机牌,那登机牌又从哪来?检票口换的,人家会先验明你的身份,确认后才会发给你登机牌。一样的处理过程,我们的登录服在验明客户端身份后,也会发给客户端一个登机牌,这个登机牌还有一个学名,叫做session key。

客户端拿着这个session key去世界服网关处就可正确登录了吗?似乎还是有个疑问,他怎么知道我这个key是不是造假的?没办法,中国的假货太多,我们不得不到处都考虑假货的问题。方法很简单,去找给他登机牌的那个检票员问一下,这张牌是不是他发的不就得了。可是,那么多的LoginServer,要一个个问下来,这效率也太低了,后面排的长队一定会开始叫唤了。那么,LoginServer将这个key存到数据库中,让网关服自己去数据库验证?似乎也是个可行的方案。

如果觉得这样给数据库带来了太大的压力的话,也可以考虑类似WorldServerMgr的做法,用一个临时的列表来保存,甚至可以将这个列表就保存到WorldServerMgr上,他正好是全区唯一的。这两种方案的本质并无差别,只是看你愿意将负载放在哪里。而不管在哪里,这个查询的压力都是有点大的,想想,全区所有玩家呢。所以,我们也可以试着考虑一种新的方案,一种不需要去全区唯一一个入口查询的方案。

那我们将这些session key分开存储不就得了。一个可行的方案是,让任意时刻只有一个地方保存一个客户端的session key,这个地方可能是客户端当前正连接着的服务器,也可以是它正要去连接的服务器。让我们来详细描述一下这个过程,客户端在LoginServer上验证通过时,LoginServer为其生成了本次会话的session key,但只是保存在当前的LoginServer上,不会存数据库,也不会发送给WorldServerMgr。如果客户端这时想要去某个游戏世界,那么他必须先通知当前连接的LoginServer要去的服务器地址,LoginServer将session key安全转移给目标服务器,转移的意思是要确保目标服务器收到了session key,本地保存的要删除掉。转移成功后LoginServer通知客户端再去连接目标服务器,这时目标服务器在验证session key合法性的时候就不需要去别处查询了,只在本地保存的session key列表中查询即可。

当然了,为了session key的安全,所有的服务器在收到一个新的session key后都会为其设一个有效期,在有效期过后还没来认证的,则该session key会被自动删除。同时,所有服务器上的session key在连接关闭后一定会被删除,保证一个session key真正只为一次连接会话服务。

7.立足文本特点探寻知识架构 篇七

一、整体观照,序列成体

教材本身有一定的知识序列,教师要首先吃透教材的顶层设计。如许多教师对当下语文苏教版教材的文体知识序列是存有抱怨的,认为这套教材按照主题内容来进行编写,文体意识不够强,甚至认为有些杂乱无章。比如八上《苏州园林》,很多老师把它当作游记散文来教,八下《我们的知识是有限的》,很多老师都把它当作议论文来教,其实这两篇文章都是说明文。

如果我们从整体上观照苏教版教材里的说明文文本,七上第三单元通过《宇宙里有些什么》让学生初步接触说明文这种文体,学生对该文体的认识可能是模糊的,但能感觉到与小学阶段大部分接触的记叙文是有所不同的。七下通过《人民英雄永垂不朽》《巍巍中山陵》《凡尔赛宫》《黄鹤楼》《于园》等说明文来展现建筑艺术的魅力,七上第四单元动物世界又通过《松鼠》《松树金龟子》《国宝——大熊猫》等说明文来介绍各具特色的小动物,并且让学生接触到了生动说明的科学小品,整整两个单元的说明文,教师可以依据文本特点,有序列、有侧重地将说明文对象的特征、说明顺序、说明方法、说明语言等渗透到教学设计中。八上的《苏州园林》与前面三篇游记散文交杂在一起,编者的意图不言而喻,是让我们更好地来区分在同样介绍景物的文章中,游记散文和说明文的不同。游记散文更多的是记录游览过程中的所见所闻,而说明文是突出说明对象的特征,如“苏州园林”是突出“无论站在哪个点上,苏州园林都是一幅完美的图画”这一特征。而且八上第六单元高新科技又是一组说明文,特别是八下的《沙漠里的奇怪现象》《我们的知识是有限的》《叫三声夸克》《宇宙里有些什么》《花儿为什么这样红》这一组说明事理的说明文,很多教师对这一单元的这组文章颇有微词,认为文体不清。其实这一组说明文正是编者的匠心独具所在,由于是说明事理的,所以与介绍建筑、动物等事物性说明文是截然不同的,说明对象一个是物,一个是事理,就说明顺序而言,前者通常采用空间顺序,而后者大多采用的是逻辑顺序,而且由于说明对象是事理,所以内在有着严密的逻辑推理。如《我们的知识是有限的》看似讲道理,是议论文,其实是通过以人类对声音和乐音成因的认识逐步深化发展而又愈感困惑的事实为例,说明我们的知识是有限的这一事理。议论文通常讲事实、摆道理,而这篇文章把人类千百年的认识史浓缩为一个人的故事,虽然人类发现声音的确经历了这样几个阶段,但这个人发现声音的过程显然是虚构的,是明显不符合议论文的文体特征的,所以这不是摆事实,而是生动说明事理的一种方式。苏教版教材由感性到理性、由个别认知到系统学习的教材编排,既符合文体知识序列规律,同时也符合学生的认知规律,而我们教师要有意识地建构微型知识系统,将知识进行有机衔接。

当然不仅仅是文体知识,修辞知识、文学知识等也可通观教材,有机形成微型序列,这样当学生拿到一篇文章后,才能对文体、对写作手法等有一定的敏锐度,阅读文章时才能像庖丁解牛,“批大郤,导大窾”“恢恢乎其于游刃必有余地矣”。这样才能做到教一篇是为了教一类文章,从而达到“教是为了不教”的终极目标。

二、随文而教,“乱”中有序

首先,随文而教要遵循文本的本身特点,如《我们家的男子汉》通过“他对食物的兴趣、他对父亲的崇拜、他对独立的要求、他的眼泪、他面对生活挑战的沉着”这五个小标题来表现小小男孩身上大大的男子汉气概,既有趣,又惹人怜爱。利用小标题来组织全文,是本文的一大写作特色,教师通常会让学生评价或替换标题,此时随文而教一些短语结构等语法知识,那么学生无论评价或替换标题时都会有意识地运用相应的语法,使得改后的短语结构更加匀称,内容表现更严谨。通过对该文本标题的学习,学生既对文本内容有了深入理解,又对偏正短语结构有了一定的认识。因此,教师需充分挖掘文本本身的写作特色,对有必要的语法等知识进行相关教学。

其次,随文而教虽不要求系统集中,但也需循序渐进。如同样是短语结构的学习,《我们家的男子汉》集中在偏正短语的学习,而《美丽的西双版纳》,由“高高望天树、竹楼映蓝天、悠悠野象谷、妩媚傣寨水、笑对生与死”五个小标题架构全文,通过改拟标题,使学生在接触过偏正短语的基础上,进一步学习主谓短语如“竹楼映蓝天”、动宾短语如“笑对生与死”。《我们家的男子汉》在七上,而《美丽的西双版纳》在八上,可见,对于语法知识的学习不需要集中一段时间去系统学习,但教师要有计划地根据文本特点随文而教相关的语法知识。

当然,不仅仅是短语的结构学习,也不仅仅是语法学习,有许多如与教材密切关联的作家作品知识、古代汉语知识等,都需要我们随文而教,也都需要我们根据文本特点,进行整体观照,探寻内在的序列。

三、打破壁垒,贯通“三维”

语文知识像语文学科的骨架,而能力、情感态度价值观等就像语文学科的血肉,它们之间并不存在孰轻孰重的问题,正是由于这三维目标的共同发展,才使得语文素养的提升在学生身上鲜活、灵动、丰富地得以实现。

很多时候,我们教师将知识与能力对立起来,认为知识是“死”的,而把能力看作是“活”的。其实知识与能力就像一张纸的两面,将知识灵活运用到各种语境中去,获取具有生命力的鲜活的知识,打破知识与能力的壁垒,在习得知识的过程中思维积极参与建构,才能提炼知识学习的“理”,从而实现转识成“智”的理想境界。如在教授《木兰诗》时,文章采用大量的铺排、对偶等来表现战前“阿爷无大儿,木兰无长兄”的无奈、四处准备作战工具的紧张忙碌、作战中木兰对家人的思念、战场的惨烈、作战后木兰的淡泊名利以及小儿女的欣喜。修辞手法用来更好地表现气氛的特点、人物的心理、细腻的情感。语言形式与语言内容是有机统一的,有的老师从语言形式入手,着眼战前、战中、战后的三处铺排,来感知文章内容,探知人物心理和人物性格。由文章略写木兰征战沙场,详写战前、战中、战后的儿女情怀来探知木兰渴望和平、愿做普通女子不愿做巾帼英雄的心声,即由文本详略安排入手来走进人物的内心世界,来探知文本真正所表现的主题。有的老师从语言内容入手,由木兰的人物形象分析,由一个女子不得不脱下红装,穿上戎装,最后又穿上女装的心路历程来总结修辞手法的运用。无论是从语言形式走向语言内容,还是从内容归结知识特点,都能让学生在有机的实践活动中习得语言形式的运用,获得分析问题的能力,得到语文素养的提升。

因此,知识是课程的根基,是形成能力和素养的源头,任何时候、任何一门学科教学都离不开知识教学。但是,语文知识教学不是简单追求知识概念的建立,也不要求知识体系的完整,而是需要教师立足教材,形成知识的序列,形成知识的微系统。更重要的是,要更加注重知识的实际运用,将其置于文本特定的情境中,用“活”方法学习“活”知识,引导学生探得语言形式与语言内容的本质联系,从而来学习语言文字的运用。

上一篇:环水保检查情况汇报下一篇:电气工程 毕业实习报告