服务器模型的类型有哪些?(服务器模型的类型有哪些选择)

网络服务器的几种并发服务模型

服务程序最为关键的设计是并发服务模型,当前有以下几种典型的模型:

- 单进程服务,使用非阻塞IO

使用一个进程服务多个客户,通常与客户通信的套接字设置为非阻塞的,阻塞只发生在select()、poll()、epoll_wait()等系统调用上面。这是一种行之有效的单进程状态机式服务方式,已被广泛采用。

缺点是它无法利用SMP(对称多处理器)的优势,除非启动多个进程。此外,它尝试就绪的IO文件描述符后,立即从系统调用返回,这会导致大量的系统调用发生,尤其是在较慢的字节传输时。

select()本身的实现也是有局限的:能打开的文件描述符最多不能超过FD_SETSIZE,很容易耗尽;每次从select()返回的描述符组中扫描就绪的描述符需要时间,如果就绪的描述符在末尾时更是如此(epoll特别彻底修复了这个问题)。

- 多进程服务,使用阻塞IO

也称作 accept/fork 模型,每当有客户连线时产生一个新的进程为之服务。这种方式有时是必要的,比如可以通过操作系统获得良好的内存保护,可以以不同的用户身份运行程序,可以让服务运行在不同的目录下面。但是它的缺点也很明显:进程比较占资源,进程切换开销太大,共享某些信息比较麻烦。Apache 1.3就使用了这种模型,MaxClients数很容易就可以达到。

- 多线程服务,使用阻塞IO

也称之 accept/pthread_create模型,有新客户来时创建一个服务线程而不是服务进程。这解决了多进程服务的一些问题,比如它占用资源少,信息共享方便。但是麻烦在于线程仍有可能消耗光,线程切换也需要开销。

- 混合服务方式

所谓的混合服务方式,以打破服务方和客户方之间严格的1:1关系。基本做法是:

新客户到来时创建新的工作线程,当该工作线程检测到网络IO会有延迟时停止处理过程,返回给Server一个延迟处理状态,同时告诉 Server被延迟的文件描述符,延迟超时时间。Server会在合适的时候返回工作线程继续处理。注意这里的工作线程不是通过 pthread_create()创建的,而是被包装在专门用于处理延迟工作的函数里。

这里还有一个问题,工作线程如何检测网络IO会有延迟?方法有很多,比如设置较短的超时时间调用poll(),或者甚至使用非阻塞IO。如果是套接字,可以设置SO_RCVTIMEO和SO_SNDTIMEO选项,这样更有效率。

除了延迟线程,Server还应提供了未完成线程的支持。

如有有特别耗费时间的操作,你可以在完成部分工作后停止处理,返回给Server一个未完成状态。这样Server会检查工作队列是否有别的线程,如果有则让它们运行,否则让该工作线程继续处理,这可以防止某些线程挨饿。

典型的一个混合服务模型开源实现ServerKit

Serverkit的这些线程支持功能可简化我们的服务程序设计,效率上应该也是有保证的。

2. 队列(queue)

ServerKit提供的队列是一个单向链表,队列的存取是原子操作,如果只有一个执行单元建议不要用,因为原子操作的开销较大。

3. 堆(heap)

malloc()分配内存有一定的局限,比如在多线程的环境里,需要序列化内存分配操作。ServerKit提供的堆管理函数,可快速分配内存,可有效减少分配内存的序列化操作,堆的大小可动态增长,堆有引用计数,这些特征比较适合多线程环境。目前ServerKit堆的最大局限是分配单元必须是固定大小。

4. 日志记录

日志被保存在队列,有一个专门的线程处理队列中的日志记录:它或者调用syslog()写进系统日志,或者通过UDP直接写到远程机器。后者更有效。

5. 读写锁

GNU libc也在pthreads库里实现了读写锁,如果定义了__USE_UNIX98就可以使用。不过ServerKit还提供了读写锁互相转换的函数,这使得锁的应用更为弹性。比如拥有读锁的若干个线程对同一个hash表进行检索,其中一个线程检索到了数据,此时需要修改它,一种办法是获取写锁,但这会导致释放读锁和获取写锁之间存在时间窗,另一种办法是使用ServerKit提供的函数把读锁转换成写锁,无疑这种方式更有效率。

除了以上这些功能,ServerKit还提供了数据库连接池的管理(当前只支持MySQL)和序列化(Sequences),如感兴趣可参见相关的API文档。

二、ServerKit服务模块编写

ServerKit由3部分组成:server程序,负责加载服务模块、解析配置文件、建立数据库连接池;libserver,动态链接库,提供所有功能的库支持,包括server本身也是调用这个库写的;API,编程接口,你编写的服务模块和ServerKit框架进行对话的接口。

ServerKit需要libConfuse解析配置文件,所以出了安装ServerKit,还需要安装libConfuse。关于libConfuse可参考 。

下面我们看一个简单的服务模块FOO:

#include confuse.h

#include server.h

static long int sleep_duration;

static int FOO_construct()

{

fprintf(stderr, \"FOO_construct\\n\");

return 1;

}

static int FOO_prestart(cfg_t *configuration)

{

fprintf(stderr, \"FOO_prestart\\n\");

return 1;

}

static void * FOO_operator(void *foobar)

{

fprintf(stderr, \"FOO_operator\\n\");

for(;;) sleep(sleep_duration);

return NULL;

}

static void FOO_report(void)

{

fprintf(stderr, \"FOO_report\\n\");

}

static cfg_opt_t FOO_config[] = {

CFG_SIMPLE_INT(\"sleep_duration\", sleep_duration),

CFG_END()

};

static char *FOO_authors[] = {\"Vito Caputo vcaputo@pengaru.com\", NULL};

SERVER_MODULE(FOO,0,0,1,\"Example module that does nothing but sleep\")

按以下方法编译:

$ gcc -c -fPIC -pthread -D_REENTRANT -g FOO.c

$ gcc -shared -lserver -lconfuse -lpthread -g -e __server_module_main -o FOO.so FOO.o

-e选项指定程序运行入口,这使得你可以直接在命令行敲 ./FOO.so 运行模块。

server程序根据环境变量SERVER_PERSONALITY_PATH定位主目录,并查找主目录下的c11n作为配置文件,动态加载的模块需放在主目录下的modules目录。

$ export SERVER_PERSONALITY_PATH=`pwd`

$ mkdir modules

$ cp FOO.so modules

$ vi c11n

c11n的内容:

identity = \"any_id\"

FOO {

sleep_duration = 1;

}

identity标识server实例,用ps可看到程序名称形如server.identity,本例为server.any_id。

执行server启动服务程序。

三、ServerKit其他功能缺陷

缺乏daemon模式;

只能运行在Linux box;

DB pool只支持MySQL;

Heap管理内存的功力有限

服务器功能类型有哪些?

服务器类型有哪些?

机架式 刀片式 塔式 机柜式

典型服务器应用

办公OA服务器

ERP服务器

WEB服务器

数据库服务器

财务服务器

邮件服务器

打印服务器

集群服务器

无盘办公系统

无盘网吧服务器

无盘教学系统

视频监控服务器

流媒体服务器

服务器类型有哪些?

你好,服务器的品牌有:

IBM Sun 惠普 戴尔 华硕 联想

英特尔 浪潮 方正 清华同方 NEC

微星 长城 宏碁 金品 致荣 赛天

五舟 超毅定制者 曙光 ……

服务器类型解释及选购要考虑的因素

在信息化日益普遍的今天,若能拥有一台功能齐备,价格合理的服务器,将是愈来愈多人关心的课题。昔日,许多人将选购一台好的PC,当作人生大事,但随着时间流转,科技日新月异,高性能的计算机设备不断更新,价格也相对不断合理化,现今无论企业或个人,都开始有机会接触PC服务器,企业为了节约成本,增加效率,必需使用服务器,而个人因为资料储存量变大,数字接口设备不断增加,例如数字相片,图形处理,高画质游戏,数据备份…等的需求,也可能开始接触入门级服务器,因此,如何选购一台好的PC服务器,将与许多人息息相关。

首先,我们必需了解何谓PC服务器?所谓PC服务器,即是Intel架构服务器,与一些大型服务器如Mainframe, Unix架构服务器等不同,前者大多运行Windows或Linux等操作系统,使用较为普遍,后者多为专业用途,如银行,大型制造业,物流业,证券…等行业使用,一般人较少有机会接触到。一般而言,PC服务器若以外型来分,大致可分为三类:

(一) 直立式服务器(塔式服务器):

为可独立放置于桌面或地面的服务器,大都具有较多的扩充槽及硬盘空间。无需额外设备,插上电即可使用,因此使用最为广泛。

(二) 机架式服务器:

为可装上机柜之服务器,主要作用为节省空间,机台高度以1U为单位,1U约44mm,因空间较局限,扩充性较受限制,例如1U的服务器大都只有1到2个PCI扩充槽。此外,散热性能成为十分重要的因素,此时,各家厂商的功力就在此展现了。缺点是需要有机柜等设备,多为服务器用量较大的企业使用。

(三) 刀片服务器:

可算是比机架式服务器更节省空间的产品。主要结构为一大型主体机箱,内部可插上许多卡片,一张卡片即相当于一台服务器。当然,散热性在此非常重要,往往各家厂商都装上大型强力风扇来散热。此型服务器虽然空间较节省,但光是主体机箱部份可能就所费不赀,除大型企业外较少使用。

了解了服务器的种类之后,如何能选购一台适用的PC服务器呢?我们可以从下列几方面来考虑:

1. 稳定性能:

这是服务器最重要的因素之一。然而,对许多人来说,“稳定”似乎是个十分抽象的名词,似乎每一家服务器厂商都在强调自己的产品十分稳定。其实,“稳定”并非完全没有脉络可寻,也并非贵的产品即是稳定者,笔者提供一些小技巧以供参考:

(1) 整体组装品质: 通常较有规模的厂家所组装的产品,有一定的品管及制造流程,因此,若可打开机箱观察,便不难发现若是布线凌乱,机箱用料单薄,组件吻合度不佳或CPU, 内存及硬盘无原厂保固贴纸等,就绝对不该将之列入考虑范围。

(2)良好的散热设计: 服务器大多需要长时间运作,因此良好的散热性能是十分重要的。散热性能可以由厂商数据,散热风力强度或实际测试得知,散热良好的服务器往往有着较佳的稳定性能。

(3) 承诺售后服务内容: 对自己所出品的产品有信心的厂家,通常会提供较好的服务内容,

(4)整体口碑: 通常服务器产品口碑十分重要,选择有人推荐的品牌或市场上较老的品牌也是一种办法。但是,有时也会有新的品牌或产品也十分优良的,这些就要靠一些专家的推荐或试用测试。

(5)权威性评比推荐: 一些权威性的杂志常常会有一些评比,也不失为一种参考依据,但最主要的还是要看一些实际运行性能测试,并多比较相关报导,才容易获......

web服务器有哪些类型

使用最多的 web server 服务器软件 有两个:微软的信息服务器(iis),和Apache。

通俗的讲,Web服务器传送(serves)页面使浏览器可以浏览,然而应用程序服务器提供的是客户端应用程序可以调用(call)的方法(methods)。确切一点,你可以说:Web服务器专门处理HTTP请求(request),但是应用程序服务器是通过很多协议来为应用程序提供(serves)商业逻辑(business logic)。

Web服务器可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求(request),会返回一个HTTP响应(response),例如送回一个HTML页面。为了处理一个请求(request),Web服务器可以响应(response)一个静态页面或图片,进行页面跳转(redirect),或者把动态响应(dynamic response)的产生委托(delegate)给一些其它的程序例如CGI脚本,JSP(JavaServer Pages)脚本,servlets,ASP(Active Server Pages)脚本,服务器端(server-side)JavaScript,或者一些其它的服务器端(server-side)技术。无论它们(译者注:脚本)的目的如何,这些服务器端(server-side)的程序通常产生一个HTML的响应(response)来让浏览器可以浏览。

要知道,Web服务器的代理模型(delegation model)非常简单。当一个请求(request)被送到Web服务器里来时,它只单纯的把请求(request)传递给可以很好的处理请求(request)的程序(译者注:服务器端脚本)。Web服务器仅仅提供一个可以执行服务器端(server-side)程序和返回(程序所产生的)响应(response)的环境,而不会超出职能范围。服务器端(server-side)程序通常具有事务处理(transaction processing),数据库连接(database connectivity)和消息(messaging)等功能。

虽然Web服务器不支持事务处理或数据库连接池,但它可以配置(employ)各种策略(strategies)来实现容错性(fault tolerance)和可扩展性(scalability),例如负载平衡(load balancing),缓冲(caching)。集群特征(clustering—features)经常被误认为仅仅是应用程序服务器专有的特征。

应用程序服务器(The Application Server)

根据我们的定义,作为应用程序服务器,它通过各种协议,可以包括HTTP,把商业逻辑暴露给(expose)客户端应用程序。Web服务器主要是处理向浏览器发送HTML以供浏览,而应用程序服务器提供访问商业逻辑的途径以供客户端应用程序使用。应用程序使用此商业逻辑就象你调用对象的一个方法(或过程语言中的一个函数)一样。

应用程序服务器的客户端(包含有图形用户界面(GUI)的)可能会运行在一台PC、一个Web服务器或者甚至是其它的应用程序服务器上。在应用程序服务器与其客户端之间来回穿梭(traveling)的信息不仅仅局限于简单的显示标记。相反,这种信息就是程序逻辑(program logic)。 正是由于这种逻辑取得了(takes)数据和方法调用(calls)的形式而不是静态HTML,所以客户端才可以随心所欲的使用这种被暴露的商业逻辑。......

网络中的服务器类型有哪些,他们各有什么用途

web服务器,用来提供网站,也就是我们现在上网看的网站都是web服务器提供的。dns服务器,提供网络dns,域名转换。ftp服务器,和web类似,它提供的是文件服务。数据库服务器,主要装数据资料的,这个没什么好说的。dhcp服务器,提供动态ip转换。主要就这些了

常见的服务器操作系统有哪些,各有什么特点?

一般的,分为两大类: 1、windows类:windows nt、windows 2000、windows 2003、windows 2008等,图形界面友好,易操作 2、unix类:ibm aix、sco unix、sco unixware、各种linux等,多用户功能强大,运行稳定,字符界面的不易操作,掌握起来有一定的难度

常用的应用服务器有哪些,各有什么功能

一般的,分为两大类: 1、windows类:windows nt、windows 2000、windows 2003、windows 2008等,图形界面友好,易操作 2、unix类:ibm aix、sco unix、sco unixware、各种linux等,多用户功能强大,运行稳定,字符界面的不易操作,掌握起来有一定的难度

电脑服务器是什么 服务器有什么功能 终端是什么

服务器是一种高性能计算机,作为网络的节点,存储、处理网络上80%的数据、信息,因此也被称为网络的灵魂。做一个形象的比喻:服务器就像是邮局的交换机,而微机、笔记本、PDA、手机等固定或移动的网络终端,就如散落在家庭、各种办公场所、公共场所等处的电话机。我们与外界日常的生活、工作中的电话交流、沟通,必须经过交换机,才能到达目标电话;同样如此,网络终端设备如家庭、企业中的微机上网,获取资讯,与外界沟通、娱乐等,也必须经过服务器,因此也可以说是服务器在“组织”和“领导”这些设备。

服务器的构成与微机基本相似,有处理器、硬盘、内存、系统总线等,它们是针对具体的网络应用特别制定的,因而服务器与微机在处理能力、稳定性、可靠性、安全性、可扩展性、可管理性等耿面存在差异很大。尤其是随着信息技术的进步,网络的作用越来越明显,对自己信息系统的数据处理能力、安全性等的要求也越来越高,如果您在进行电子商务的过程中被黑客窃走密码、损失关键商业数据;如果您在自动取款机上不能正常的存取,您应该考虑在这些设备系统的幕后指挥者————服务器,而不是埋怨工作人员的素质和其他客观条件的限制。

局域网中服务器有哪些类型?

web服务器提供网页浏览的,

ftp服务器提供文件上传下载的,

dhcp服务器提供动态分配ip地址的,

dns服务器提供域名解析服务的,

proxy提供代理功能的,

email提供邮件服务的等等 这是按逻辑分的,其实这些服务可以在一台电脑上实现,当然要考虑访问量大小

常用的web服务器软件有哪些

(1)ApacheApache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上。Apache源于NCSAd服务器,经过多次修改,成为世界上最流行的Web服务器软件之一。Apache取自\"a patchy server\"的读音,意思是充满补丁的服务器,因为它是自由软件,所以不断有人来为它开发新的功能、新的特性、修改原来的缺陷。Apache的特点郸简单、速度快、性能稳定,并可做代理服务器来使用。(2)IIS是英文Internet Information Server的缩写,译成中文就是\"Internet信息服务\"的意思。它是微软公司主推的服务器,最新的版本是Windows2008里面包含的IIS 7,IIS与Window Server完全集成在一起,因而用户能够利用Windows Server和NTFS(NT File System,NT的文件系统)内置的安全特性,建立强大,灵活而安全的Internet和Intranet站点。(3)GFEGoogle的web服务器,用户数量激增。目前紧逼iis。(4)Nginx不仅是一个小巧且高效的HTTP服务器,也可以做一个高效的负载均衡反向代理,通过它接受用户的请求并分发到多个Mongrel进程可以极大提高Rails应用的并发能力。(5)Ligd是由德国人 Jan Kneschke 领导开发的,基于BSD许可的开源WEB服务器软件,其根本的目的是提供一个专门针对高性能网站,安全、快速、兼容性好并且灵活的web server环境。具有非常低的内存开销,CPU占用率低,效能好,以及丰富的模块等特点。Ligd 是众多OpenSource轻量级的web server中较为优秀的一个。支持FastCGI, CGI, Auth, 输出压缩(output press), URL重写, Alias等重要功能。(6)Zeus是一个运行于Unix下的非常优秀的Web Server,据说性能超过Apache,是效率最高的Web Server之一。(7)Sun的Java系统Web服务器也就是以前的Sun ONE Web Server。主要出现在那些运行Sun的Solaris操作系统的关键任务级Web服务器上。它最新的版本号是6.1,可以支持x86版本Solaris,Red Hat Linux,HP-UX 11i, IBM AIX,甚至可以支持Windows,但它的大多数用户都选择了SPARC版本的Solaris操作系统。(8)Resin提供了最快的jsp/servlets运行平台。在java和javascript的支持下,Resin可以为任务灵活选用合适的开发语言。Resin的一种先进的语言XSL(XML stylesheet language)可以使得形式和内容相分离。(9)Jetty是一个开源的servlet容器,它为基于Java的web内容,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和web连接。(10)BEA WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器。将Java的动态功能和Java Enterprise标准的安全性引入大型网络应用的开发、集成、部署和管理......

云计算主要有3种服务类型,每种类型的功能和服务对象都是什么?

软件即服务(Software as a Service,缩写SaaS)

软件即服务是普通消费者可以感知到的云计算,它的代表有Dropbox,还有国内用户熟悉的百度云、腾讯微云等。这种云计算最大的特征就是消费者并不购买任何实体的产品,而是购买具有与实体产品同等功能的服务。

以前,我们是花钱购买的是服务器上的存储空间。现在,我们花钱购买的是Dropbox的存储服务。表面上看,两者没有实际的区别。但是换一个角度来看,两者却完全不同。以前,我们花钱购买服务器上的存储空间,假设是空间容量是10G,我们是真正的买到了服务器上的10G空间。如果我们不上传文件的话,那么服务器上的这10G空间就是空的。现在,我们购买Dropbox的存储服务,假设空间容量还是10G,我们却并没有真正的买到Dropbox服务器上10G的空间,我们买到的是10G空间的服务。也就是说,如果我们上传文件,Dropbox会将文件分开放在任何地方的任何服务器上,如果我们不上传文件,Dropbox的服务器上就根本没有属于我们的任何空间。

平台即服务(Platform as a Service,缩写PaaS)

与软件即服务不同,平台即服务是面向开发者的云计算。这种云计算最大的特征是它自带开发环境,并向开发者提供开发工具包。它的代表有Google的GAE(Google App Engine),还有国内的百度的BAE、新浪的SAE等。

平台即服务与软件即服务之间可以相互转换。如果是消费者,购买Dropbox的服务,那Dropbox就是软件即服务。如果是开发者,利用Dropbox提供的开发包借助Dropbox的服务开发自己的服务,那么Dropbox本身就是平台即服务,构筑在Dropbox之上的开发者的服务就是软件即服务。

以前,开发者如果要搭建一个网站,需要做很多准备工作,比如购买服务器,安装操作系统,搭建开发环境等等。现在,开发者如果购买平台即服务云计算,就可以省去上面费时费力的准备工作,直接进行网站的开发。不仅如此,开发者还可以使用各种现成的服务,比如GAE会向开发者提供Google内部使用的先进的开发工具和领先的大数据技术。这一切都使得网站开发变得比以前轻松很多,这也是云计算时代互联网更加繁荣的原因之一。

基础架构即服务(Infrastructure as a Service,缩写IaaS)

基础架构即服务一般面向的是企业用户,它的代表有Amazon的AWS(Amazon Web Service),还有国内的PPPCloud等。

这种云计算最大的特征在于,它并不像传统的服务器租赁商一样出租具体的服务器实体,它出租的是服务器的计算能力和存储能力。AWS将Amazon计算中心的所有的服务器的计算能力和存储能力整合成一个整体,然后将其划分为一个个虚拟的实例,每一个实例代表着一定的计算能力和存储能力。购买AWS云计算服务的公司就以这些实例就作为计量单位。

基础架构即服务与平台即服务有显著的区别,基础架构即服务提供的只有计算能力和存储能力的服务,平台即服务提供的除了计算能力和存储能力的服务,还提供给开发者的完备的开发工具包和配套的开发环境。也就是说,开发者使用平台即服务时,可以直接开始进行开发工作。而使用基础架构即服务时,则必须先进行如安装操作系统、搭建开发环境等准备工作。

基础架构即服务是云计算的基石,平台即服务和软件即服务构建在它的上面,分别为开发者和消费者提供服务,而它本身则为大数据服务。...

客户机/服务器模式有哪些?

如电子邮件交换,Web访问和数据库访问功能,是建立在客户服务器模式。用户访问银行服务,从他们的电脑使用Web浏览器客户端发送请求到Web服务器在银行。该方案可能反过来请求转发给它自己的数据库客户端程序,在另一家银行的计算机发送一个请求到数据库服务器检索帐户信息。该余额返回到银行的数据库客户端,这反过来又服务于它的回Web浏览器客户端显示结果给用户。客户机服务器模式已成为网络计算的核心思想之一。许多商业应用程序被写入今天使用客户服务器模型。所以,做互联网的主要应用协议,如的HTTP,SMTP,Telnet和DNS的。

客户端和服务器之间的交互是经常使用序列图描述。序列图是在统一建模语言规范。

特定类型的客户包括Web浏览器,电子邮件客户端和在线聊天的客户。

特定类型的服务器包括Web服务器,FTP服务器,应用服务器,数据库服务器,域名服务器,邮件服务器,文件服务器,打印服务器和终端服务器。大多数Web服务也是服务器类型。

几种经典的网络服务器架构模型的分析与比较

相比于传统的网络编程方式,事件驱动能够极大的降低资源占用,增大服务接待能力,并提高网络传输效率。 关于本文提及的服务器模型,搜索网络可以查阅到很多的实现代码,所以,本文将不拘泥于源代码的陈列与分析,而侧重模型的介绍和比较。使用 libev 事件驱动库的服务器模型将给出实现代码。 本文涉及到线程 / 时间图例,只为表明线程在各个 IO 上确实存在阻塞时延,但并不保证时延比例的正确性和 IO 执行先后的正确性;另外,本文所提及到的接口也只是笔者熟悉的 Unix/Linux 接口,并未推荐 Windows 接口,读者可以自行查阅对应的 Windows 接口。阻塞型的网络编程接口几乎所有的程序员第一次接触到的网络编程都是从 listen()、send()、recv()等接口开始的。使用这些接口可以很方便的构建服务器 /客户机的模型。我们假设希望建立一个简单的服务器程序,实现向单个客户机提供类似于“一问一答”的内容服务。图1. 简单的一问一答的服务器 /客户机模型我们注意到,大部分的 socket接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是 IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统调用获得结果或者超时出错时才返回。实际上,除非特别指定,几乎所有的 IO接口 (包括 socket 接口 )都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用 send()的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。这给多客户机、多业务逻辑的网络编程带来了挑战。这时,很多程序员可能会选择多线程的方式来解决这个问题。多线程服务器程序 应对多客户机的网络应用,最简单的解决方式是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。 具体使用多进程还是多线程,并没有一个特定的模式。传统意义上,进程的开销要远远大于线程,所以,如果需要同时为较多的客户机提供服务,则不推荐使用多进程;如果单个服务执行体需要消耗较多的 CPU 资源,譬如需要进行大规模或长时间的数据运算或文件访问,则进程较为安全。通常,使用 pthread_create () 创建新线程,fork() 创建新进程。 我们假设对上述的服务器 / 客户机模型,提出更高的要求,即让服务器同时为多个客户机提供一问一答的服务。于是有了如下的模型。图2. 多线程服务器模型 在上述的线程 / 时间图例中,主线程持续等待客户端的连接请求,如果有连接,则创建新线程,并在新线程中提供为前例同样的问答服务。 很多初学者可能不明白为何一个 socket 可以 accept 多次。实际上,socket 的设计者可能特意为多客户机的情况留下了伏笔,让 accept() 能够返回一个新的 socket。下面是 accept 接口的原型: int accept(int s, struct sockaddr *addr, socklen_t *addrlen); 输入参数 s 是从 socket(),bind() 和 listen() 中沿用下来的 socket 句柄值。执行完 bind() 和 listen() 后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列。调用 accept() 接口正是从 socket s 的请求队列抽取第一个连接信息,创建一个与 s 同类的新的 socket 返回句柄。新的 socket 句柄即是后续 read() 和 recv() 的输入参数。如果请求队列当前没有请求,则 accept() 将进入阻塞状态直到有请求进入队列。 上述多线程的服务器模型似乎完美的解决了为多个客户机提供问答服务的要求,但其实并不尽然。如果要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而线程与进程本身也更容易进入假死状态。 很多程序员可能会考虑使用“线程池”或“连接池”。“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。这两种技术都可以很好的降低系统开销,都被广泛应用很多大型系统,如 websphere、tomcat 和各种数据库等。 但是,“线程池”和“连接池”技术也只是在一定程度上缓解了频繁调用 IO 接口带来的资源占用。而且,所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。 对应上例中的所面临的可能同时出现的上千甚至上万次的客户端请求,“线程池”或“连接池”或许可以缓解部分压力,但是不能解决所有问题。 总之,多线程模型可以方便高效的解决小规模的服务请求,但面对大规模的服务请求,多线程模型并不是最佳方案。下一章我们将讨论用非阻塞接口来尝试解决这个问题。使用select()接口的基于事件驱动的服务器模型 大部分 Unix/Linux 都支持 select 函数,该函数用于探测多个文件句柄的状态变化。下面给出 select 接口的原型: FD_ZERO(int fd, fd_set* fds) FD_SET(int fd, fd_set* fds) FD_ISSET(int fd, fd_set* fds) FD_CLR(int fd, fd_set* fds) int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 这里,fd_set 类型可以简单的理解为按 bit 位标记句柄的队列,例如要在某 fd_set 中标记一个值为 16 的句柄,则该 fd_set 的第 16 个 bit 位被标记为 1。具体的置位、验证可使用 FD_SET、FD_ISSET 等宏实现。在 select() 函数中,readfds、writefds 和 exceptfds 同时作为输入参数和输出参数。如果输入的 readfds 标记了 16 号句柄,则 select() 将检测 16 号句柄是否可读。在 select() 返回后,可以通过检查 readfds 有否标记 16 号句柄,来判断该“可读”事件是否发生。另外,用户可以设置 timeout 时间。 下面将重新模拟上例中从多个客户端接收数据的模型。图4.使用select()的接收数据模型 上述模型只是描述了使用 select() 接口同时从多个客户端接收数据的过程;由于 select() 接口可以同时对多个句柄进行读状态、写状态和错误状态的探测,所以可以很容易构建为多个客户端提供独立问答服务的服务器系统。图5.使用select()接口的基于事件驱动的服务器模型 这里需要指出的是,客户端的一个 connect() 操作,将在服务器端激发一个“可读事件”,所以 select() 也能探测来自客户端的 connect() 行为。 上述模型中,最关键的地方是如何动态维护 select() 的三个参数 readfds、writefds 和 exceptfds。作为输入参数,readfds 应该标记所有的需要探测的“可读事件”的句柄,其中永远包括那个探测 connect() 的那个“母”句柄;同时,writefds 和 exceptfds 应该标记所有需要探测的“可写事件”和“错误事件”的句柄 ( 使用 FD_SET() 标记 )。 作为输出参数,readfds、writefds 和 exceptfds 中的保存了 select() 捕捉到的所有事件的句柄值。程序员需要检查的所有的标记位 ( 使用 FD_ISSET() 检查 ),以确定到底哪些句柄发生了事件。 上述模型主要模拟的是“一问一答”的服务流程,所以,如果 select() 发现某句柄捕捉到了“可读事件”,服务器程序应及时做 recv() 操作,并根据接收到的数据准备好待发送数据,并将对应的句柄值加入 writefds,准备下一次的“可写事件”的 select() 探测。同样,如果 select() 发现某句柄捕捉到“可写事件”,则程序应及时做 send() 操作,并准备好下一次的“可读事件”探测准备。下图描述的是上述模型中的一个执行周期。图6. 一个执行周期 这种模型的特征在于每一个执行周期都会探测一次或一组事件,一个特定的事件会触发某个特定的响应。我们可以将这种模型归类为“事件驱动模型”。 相比其他模型,使用 select() 的事件驱动模型只用单线程(进程)执行,占用资源少,不消耗太多 CPU,同时能够为多客户端提供服务。如果试图建立一个简单的事件驱动的服务器程序,这个模型有一定的参考价值。 但这个模型依旧有着很多问题。 首先,select() 接口并不是实现“事件驱动”的最好选择。因为当需要探测的句柄值较大时,select() 接口本身需要消耗大量时间去轮询各个句柄。很多操作系统提供了更为高效的接口,如 linux 提供了 epoll,BSD 提供了 kqueue,Solaris 提供了 /dev/poll …。如果需要实现更高效的服务器程序,类似 epoll 这样的接口更被推荐。遗憾的是不同的操作系统特供的 epoll 接口有很大差异,所以使用类似于 epoll 的接口实现具有较好跨平台能力的服务器会比较困难。 其次,该模型将事件探测和事件响应夹杂在一起,一旦事件响应的执行体庞大,则对整个模型是灾难性的。如下例,庞大的执行体 1 的将直接导致响应事件 2 的执行体迟迟得不到执行,并在很大程度上降低了事件探测的及时性。图7. 庞大的执行体对使用select()的事件驱动模型的影响 幸运的是,有很多高效的事件驱动库可以屏蔽上述的困难,常见的事件驱动库有 libevent 库,还有作为 libevent 替代者的 libev 库。这些库会根据操作系统的特点选择最合适的事件探测接口,并且加入了信号 (signal) 等技术以支持异步响应,这使得这些库成为构建事件驱动模型的不二选择。下章将介绍如何使用 libev 库替换 select 或 epoll 接口,实现高效稳定的服务器模型。使用事件驱动库libev的服务器模型 Libev 是一种高性能事件循环 / 事件驱动库。作为 libevent 的替代作品,其第一个版本发布与 2007 年 11 月。Libev 的设计者声称 libev 拥有更快的速度,更小的体积,更多功能等优势,这些优势在很多测评中得到了证明。正因为其良好的性能,很多系统开始使用 libev 库。本章将介绍如何使用 Libev 实现提供问答服务的服务器。 (事实上,现存的事件循环 / 事件驱动库有很多,作者也无意推荐读者一定使用 libev 库,而只是为了说明事件驱动模型给网络服务器编程带来的便利和好处。大部分的事件驱动库都有着与 libev 库相类似的接口,只要明白大致的原理,即可灵活挑选合适的库。) 与前章的模型类似,libev 同样需要循环探测事件是否产生。Libev 的循环体用 ev_loop 结构来表达,并用 ev_loop( ) 来启动。 void ev_loop( ev_loop* loop, int flags ) Libev 支持八种事件类型,其中包括 IO 事件。一个 IO 事件用 ev_io 来表征,并用 ev_io_init() 函数来初始化: void ev_io_init(ev_io *io, callback, int fd, int events) 初始化内容包括回调函数 callback,被探测的句柄 fd 和需要探测的事件,EV_READ 表“可读事件”,EV_WRITE 表“可写事件”。 现在,用户需要做的仅仅是在合适的时候,将某些 ev_io 从 ev_loop 加入或剔除。一旦加入,下个循环即会检查 ev_io 所指定的事件有否发生;如果该事件被探测到,则 ev_loop 会自动执行 ev_io 的回调函数 callback();如果 ev_io 被注销,则不再检测对应事件。 无论某 ev_loop 启动与否,都可以对其添加或删除一个或多个 ev_io,添加删除的接口是 ev_io_start() 和 ev_io_stop()。 void ev_io_start( ev_loop *loop, ev_io* io ) void ev_io_stop( EV_A_* ) 由此,我们可以容易得出如下的“一问一答”的服务器模型。由于没有考虑服务器端主动终止连接机制,所以各个连接可以维持任意时间,客户端可以自由选择退出时机。图8. 使用libev库的服务器模型 上述模型可以接受任意多个连接,且为各个连接提供完全独立的问答服务。借助 libev 提供的事件循环 / 事件驱动接口,上述模型有机会具备其他模型不能提供的高效率、低资源占用、稳定性好和编写简单等特点。 由于传统的 web 服务器,ftp 服务器及其他网络应用程序都具有“一问一答”的通讯逻辑,所以上述使用 libev 库的“一问一答”模型对构建类似的服务器程序具有参考价值;另外,对于需要实现远程监视或远程遥控的应用程序,上述模型同样提供了一个可行的实现方案。 总结 本文围绕如何构建一个提供“一问一答”的服务器程序,先后讨论了用阻塞型的 socket 接口实现的模型,使用多线程的模型,使用 select() 接口的基于事件驱动的服务器模型,直到使用 libev 事件驱动库的服务器模型。文章对各种模型的优缺点都做了比较,从比较中得出结论,即使用“事件驱动模型”可以的实现更为高效稳定的服务器程序。文中描述的多种模型可以为读者的网络编程提供参考价值。

未经允许不得转载:便宜VPS网 » 服务器模型的类型有哪些?(服务器模型的类型有哪些选择)