前段时间做了个简单的dtwisted项目,只有个雏形,高层点的东西就没有了。
以前用ACE做过小型游戏服务器、视频转发服务器,比较熟悉点的是reactor模式。其间也尝试过proactor,一知半解不得要领,于是放弃了。
今天工作闲暇尝试用D语言实现目前工作中用到的文件上传服务器,有了一些思考。
下面还是先为D语言做点广告。稍后回来。。。
自从用了D语言以后,我可以更加方便地尝试一些想法了,用C/C++实现很多东西都比较麻烦,而且即便实现出来也必定有许多看不过眼的东西和实现方式。使用C++开发有几年了,从我接触的同事实现的代码来看,包括我自己的代码,基本上没有能让我看过以后觉得“还行”的代码,光是Big Three就够伤脑筋的了。使用D语言以后,我自己觉得要考虑的细节少多了,更多时候我是在考虑如何架构。从开发效率上来讲,D已经足够快了,我甚至觉得已经不比一些脚本语言慢。从维护成本和运行效率上来讲,它都足以让你满意。
欢迎回来。。
通常网络服务器在并发连接比较少的时候,根本不需要考虑得太多,我们可以用单线程select+阻塞操作,也可以单线程+非阻塞,还可以多线程(每连接一线程或是线程池都不麻烦)。当并发连接数比较多的时候,几个问题就出来了:
1、单个连接传输效率下降。这个可能不光是并发数多引起的,也可能是外网带宽引起的。
2、连接数过多。每连接一线程导致线程开销过大,过多的线程同时操作可以引起IO性能急剧下滑。用线程池阻塞方式处理?可能几个慢客户就拖慢了整个服务器,实际上服务器并无负担,但线程全被占用。
3、文件上传服务器每个客户占用时间都比较多,采用每连接一线程可能导致每个客户传输效率都下降,采用线程池又只能同时处理有限的连接数。
以上几个问题在使用reactor模式后大部分可以解决掉。reactor的基本方式是使用事件方式,可以单线程处理所有连接,由于它只处理有事件的socket,所以不会长时间占用线程。如果在业务逻辑中有耗时操作,或者是IO等待,还可以实现多线程的reactor,相当于是实现了一个线程池,同时又没有上面所说的线程方式的缺点。
回到今天的试验,打算用dtwisted实现目前的文件上传服务器。文件上传服务器目前是基于短连接的,每个连接建立以后,发送一个包头。这个包头是通用格式,首先是包头长度,有了它就可以解出完整的包头,包头里面包含上传路径、文件长度和文件签名。
使用dtwisted,直观的实现方式是从Protocol上先实现一个通用的解包头的类,所有需要解包头的协议都从它上面派生。dataReceived方法里面先判断包头长度是否已经收齐,通常这要占用2-4字节。如果收齐了长度,就进入收包头状态,直到包长度收完,然后开始处理包。由于包类型可能有多种,方便以后扩充,所以从收取包到解出包头都是一个同样的模式,写成一个基类供业务逻辑类派生使用。
目前为止这个模型是合理的,我甚至把消息类都写成接口,这样不同的解包方法都可以兼容。
不过接下来一个需求打乱了这个过程。上传消息和其它几个消息不一样的地方,是包头后面直接附加了文件内容。由于前面进行了封装,所以包的处理方法的参数就是包对象,不再包含socket或transport对象,使得接收文件内容有了麻烦。当然我也可以直接调用transport来收取,但总觉得这样和基类实现依赖太高。同时这个模式还有几个缺点:
1、dataReceived要处理当前状态,这种状态的处理增加了复杂度。
2、即便可以直接调用transport来收取文件,但由于是单线程,这会导致所有其它客户都会被阻塞,违背了使用reactor的本意。
3、类层次过多,每个层实现的功能太少。
基于这几个缺点,于是想到另一种实现方式。在连接建立时,服务器发起一个读请求,指示该读取4字节(包长),并传递一个处理方法委托。当该连接收齐这4字节时,调用处理方法。这个处理方法把这4字节转成包长,接着发起一个读请求,指示该读取这么多字节的包内容。再一次收齐时,就开始解包及处理过程。如果收到的是上传消息,发起一个读取文件内容的请求,指示读取指定长度,比如是40k。在读取到文件内容以后,调用处理方法写入文件。当然一次收齐40K才处理也不合理,但收包头的过程中又希望它收齐才处理,于是在发起读请求时指定一个参数,说明是全部读取完毕才处理,还是有一点就处理一次。
上面这个过程基本上是状态方式的一种升级,发起请求就包含了这个状态,只不过现在是隐式的和看起来更合理的。
终于整个过程合理了。仔细想了一下,这不就是proactor吗?proactor本身的实现还可以优化,只有发起过读请求的连接才会加入到事件检查中,效率上可能会有优化。
分享到:
相关推荐
在这种模式下,所有的游戏逻辑和服务都集中在一台或多台中央服务器上。优点在于管理简单、易于实现;缺点是随着玩家数量的增长,服务器负载压力增大,容易造成性能瓶颈。 2. **分布式架构**:为了解决集中式架构中...
代理服务器,也称为中间服务器,是网络通信中的一种常见架构模式。在网络游戏中,代理服务器主要承担以下职责: 1. **负载均衡**:当大量玩家同时在线时,代理服务器可以分散玩家请求到不同的游戏服务器,避免单个...
这种架构模式强调了业务能力的划分,并通过服务的细粒度管理,可以实现快速迭代和持续交付。 基于空间的架构是一种将系统架构视为虚拟或实际空间,其中计算实体(如进程或对象)在空间中定位和交互的架构模式。这种...
通常,网络游戏会采用客户端/服务器(C/S)的架构模式,其中服务器端负责处理大量游戏逻辑、玩家交互以及维护游戏状态等任务。 在本篇文献中,作者杨玲提出了高性能网络游戏服务器的架构设计,这一设计针对游戏...
本资料"几种经典的网络服务器架构模型的分析与比较共5页.pdf.zip"聚焦于探讨几种主流的服务器架构模式,并进行深入的对比,旨在帮助读者理解每种架构的优缺点及其适用场景。 1. 单体架构:这是最基础的架构模型,...
这种架构模式有利于减少硬件依赖,提高网络的灵活度和动态适应能力。软件化能够实现网络资源的高效分配和网络功能的灵活调整。 2. 高频段的利用:5G网络为了实现更高的数据传输速率,需要利用高频段(毫米波)来...
### 架构模式介绍 #### 一、管道过滤模式 管道过滤模式是一种常见的软件架构模式,主要用于处理数据流。在这种模式中,系统被分解为一系列的功能模块,每个模块都负责处理特定的数据转换任务。 **特点:** - **...
一,棋牌类服务器的特点 1,棋牌类不分区不分服 2,房间模式 3,每个房间的操作必须是顺序性 二,需要解决的技术点 1,数据共享 2,如何进入房间 3,保证房间操作的顺序性 三,系统架构 。。。。。。
在构建中小型服务器网络架构时,通常的目标是提高系统的可靠性和性能,这主要通过采用服务器集群、冗余设备和负载均衡技术来实现。本篇将详细探讨这些关键知识点。 首先,服务器集群是一种将多台服务器连接在一起,...
下面将详细探讨游戏服务器架构的关键要素和常见设计模式。 1. **分布式架构**:在大型在线游戏中,单一服务器往往无法承受大量并发玩家的压力,因此通常采用分布式架构。这种架构将服务器功能分解到多个独立的...
系统选用了优秀的 Microsoft Visual C++.net2003,系统采用客户端/服务器(C/S)编程模式,TCP/IP协议作为客户端和服务器的通信网络层,运用具有性 能 最 优 的 完 成 端 口(IOCP:Input/Output Completion Port)...
服务器架构是指将不同的硬件设备、软件程序以及网络资源有机地结合起来,以实现一定的业务目标和功能。一个好的服务器架构设计,需要考虑高性能、高可用性、可扩展性、安全性和管理性等多方面因素。 在本文中,...
例如,客户-服务器架构适合于分布式系统,而微服务架构则强调服务的独立部署和解耦。 其次,论文可能会讨论基于网络的软件架构设计,这通常指的是利用互联网技术构建的分布式系统。在网络架构中,组件分布在不同的...
- **服务网格模式**:解释了服务网格如何为微服务间通信提供透明的网络服务。 重构到微服务模式: - **反腐败层模式**:帮助在服务之间实现有效的数据通信,尤其是在遗留系统和微服务之间。 - **绞杀者应用模式**:...
AWS混合网络设计架构模式主要关注如何将本地数据中心与Amazon Web Services (AWS)的云环境无缝连接,以便在公共云和私有基础设施之间高效地传输数据。这种架构的关键组件包括Direct Connect、Direct Connect Gateway...
3. **服务器架构**:讨论不同类型的服务器架构,如主从服务器模型、P2P(对等网络)架构、分布式服务器等,以及每种架构在可扩展性、负载均衡和数据一致性方面的特点。 4. **游戏逻辑分发**:阐述如何在客户端和...