I/O服务器

2024-10-13

I/O服务器(精选8篇)

I/O服务器 篇1

从1990年NeXT计算机公司开发出第一个Web服务器和第一个Web浏览器以来,互联网的发展已经经历了23年。而2005年左右开始发展的Web 2.0又开辟了互联网发展史上的一个新的时代。Web 2.0,指的是一个利用Web的平台,由用户主导生成内容的互联网产品模式,为了区别传统的由网站雇员主导生成内容而定义为Web 2.0。Web 2.0是网络运用的新时代,网络成为了新的平台,内容因为每位用户的参与而产生,参与所产生的个人化内容,借由人与人(P2P)的分享(Share),形成了现在Web 2.0的世界。由于用户和网站之间的互动增强,用户的数量和请求量急剧增加,传统的多线程和多进程方法实现的Web服务器已经难以满足巨大的并发请求。而大部分Web服务的性能瓶颈主要集中在I/O处理和数据库查询处理,所以解决这两个问题就成为解决Web服务器性能问题的主要途径。大量的数据库查询现在广泛采用内存数据库(Memory DB)和非关系数据库(NoSql)技术,以及缓存(Cache)技术,已经的到了相当不错的解决。I/O操作就成为提高服务器性能的最重要的目标。尤其是面对突发的访问高峰,很多大型网站都难以应对。在2009年美国总统奥巴马就职演说的那天,Twitter网站的访问高峰达到每秒钟收到350条新信息,平均每条被发送120次,Twitter网站每秒钟需要发送350×120=42 000条短信。由于Twitter网站使用的Apache服务器是采用工作进程(Worker)来处理请求,每个Apache服务器实例最多可以容纳4 000个并发连接,所以Twitter的做法就是在预计的高峰时段大量部署Apache服务器实例。这种做法显然效率不是很好。而异步I/O则是解决高并发访问的一个很好的手段。

1 异步I/O介绍

异步I/O,又称为non-blocking I/O,是指程序的运行不需要等待IO完成之后才能够继续进行。而同步I/O(也称为blocking I/O),程序运行需等待I/O完成之后才能继续,在等待的这段时间可能被操作系统挂起(idle)。这样当该程序包含多个I/O操作的话,程序运行的很大部分时间浪费在了I/O等待上,无法有效地响应多个并发的client请求。

异步化方式针对高并发的分布式系统,采用非阻塞方式,接受线程和工作线程分离,提高整个系统的吞吐量。好处是,整个系统的可用性大幅增加,系统之间耦合度大幅降低,并且有比较高的吞吐量,各个系统能高速运转,不会相互等待资源,可以充分利用资源。同时整个系统也可以有很好的伸缩性。

2 应用场景

2.1 C10K和C500K问题

网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被称为C10K问题(The C10K problem)。C10K问题的最大特点是:设计不够良好的程序,其性能和连接数及机器性能的关系往往是非线性的。例如,如果没有考虑过C10K问题,一个经典的基于select的程序能在旧服务器上很好处理1 000并发的吞吐量,它在2倍性能新服务器上往往处理不了并发2 000的吞吐量。这是因为在策略不当时,大量操作的消耗和当前连接数n成线性相关。会导致单个任务的资源消耗和当前连接数的关系会是O(n)。而服务程序需要同时对数以万计的socket进行I/O处理,积累下来的资源消耗会相当可观,这显然会导致系统吞吐量不能和机器性能匹配。为解决这个问题,必须改变对连接提供服务的策略。

由于客户端数量的激增,近年来又有人提出了C500K问题,Web服务器面对高并发访问的性能问题更加突出。

2.2 HTTP长连接

所谓HTTP长连接,指在一个连接上可以连续发送多个数据包,然后断开连接,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。短连接是指通信双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。长连接和传统HTTP连接的对比见图1。

Web 2.0系统和用户之间交互非常频繁。比如基于位置的服务(LBS),用户不停地向系统发送自己的位置数据,系统根据用户所在的位置采取适当的操作。如果采用传统的每个请求发送一个新的连接,系统的并发连接会非常高,而且由于TCP协议需要三次握手,消耗了大量的网络资源,导致服务器整体负载性能减弱。采用HTTP 1.1协议的长连接,每个用户与系统之间长期保持一个TCP连接,用户和系统之间的网络交互速度和性能都会大大提高。

但是使用长连接会造成每个在线用户都与系统保持一个连接,如果在线用户数量太大,比如新浪微博的在线人数在2012年7月28日伦敦奥运会开幕式期间超过400万,传统的基于多进程或多线程的Web服务器根本无法应对。

2.3 Comet请求和消息推送

Comet是基于HTTP长连接的“服务器推”技术,是一种新的Web应用架构。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet架构非常适合事件驱动的Web应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和Web版在线游戏等。服务器推送现在一般采用基于AJAX的长轮询(long-polling)方式实现。

使用AJAX实现“服务器推”与传统的AJAX应用不同之处在于:

服务器端会阻塞请求直到有数据传递或超时才返回。

客户端JavaScript响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。

当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取回。

可以发现,这种消息推送技术也使用长连接,如果客户端数量庞大,单服务器需要承受数10万的长连接才能达到要求。

3 现有实现

3.1 底层内核实现

上文所描述的场景有一个共同的特点,就是服务器要承受庞大的并发连接数量。针对以上需求,业界开发了一系列的高并发高性能服务器。本质上,这些高并发服务器底层都需要操作系统内核级别的高性能异步I/O系统支持,在Windows,Linux,BSD三种体系的操作系统下分别是IOCP,epoll和kqueue。

epoll是一个事件驱动库,它是在Linux 2.5.44中引入的,它属于poll的一个变种。传统的poll和select库,它们的最大的问题就在于效率。它们的处理方式都是创建一个事件列表,然后把这个列表发给内核,返回的时候,再去轮询检查这个列表,这样在描述符比较多的应用中,效率就显得比较低下了。一种比较好的做法是,把描述符列表交给内核,一旦有事件发生,内核把发生事件的描述符列表通知给进程,这样就避免了轮询整个描述符列表。epoll就是这样一种模型。

epoll比较传统的select/poll有以下优点:

支持一个进程打开大数目的socket描述符(FD)。select一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目远大于2 048,在1 GB内存的机器上大约是10万左右。

I/O效率不随FD数目增加而线性下降。传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对“活跃”的socket进行操作,只有“活跃”的socket才会主动的去调用callback函数,其他idle状态socket则不会。

使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。

BSD系统的kqueue和Windows系统的IOCP原理和epoll相似,这里不做介绍。

3.2 应用开发接口

3.2.1 Libevent

Libevent是一个异步事件处理软件库,以BSD许可证发布。适用于windows,linux,bsd等多种平台,内部使用select,epoll,kqueue等系统调用管理事件机制。著名分布式缓存软件mem cached也是Libevent based,而且Libevent在使用上可以做到跨平台,对于开发者是一个很好的选择。

3.2.2 Gevent

Gevent是一个基于greenlet的Python的并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效。Gevent具有基于libevent的快速的事件循环机制;基于greenlet的轻量级执行单元;使用Python标准库形式的API;SSL支持;使用libevent-dns进行DNS查询;最重要的一点是它的Monkey patch工具,可以将第三方库协程化。

3.2.3 Tornado

Tornado是FriendFeed使用的可扩展的非阻塞式Web服务器及其相关工具的开源版本。这个Web框架看起来有些像web.py或者Google的web.app,不过为了能有效利用非阻塞式服务器环境,这个Web框架还包含了一些相关的有用工具和优化。

Tornado和现在的主流Web服务器框架(包括大多数Python的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其非阻塞的方式和对epoll的运用,Tornado每秒可以处理数以千计的连接,这意味着对于实时Web服务来说,Tornado是一个理想的Web框架。开发Tornado Web服务器的主要目的就是为了处理FriendFeed的实时功能———在FriendFeed的应用里每一个活动用户都会保持着一个服务器连接。

3.3 Web服务器

3.3.1 Nginx

Nginx是一款由俄罗斯程序员Igor Sysoev所开发轻量级的网页服务器、反向代理服务器以及电子邮件(IMAP/POP3)代理服务器。起初是供俄国大型的门户网站及搜索引擎Rambler(俄语:Рамблер)使用。此软件BSD-like协议下发行,可以在UNIX,GNU/Linux,BSD,Mac OS X,Solaris,以及Microsoft Windows等操作系统中运行。

Nginx相较于Apache,Lighttpd具有占有内存少,稳定性高等优势,并且依靠并发能力强,丰富的模块库以及友好灵活的配置而闻名。在Linux操作系统下,Nginx使用epoll事件模型,得益于此,Nginx在Linux操作系统下效率相当高。同时Nginx在OpenBSD或FreeBSD操作系统上采用类似于epoll的高效事件模型kqueue。Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率。它支持内核Poll模型,能经受高负载的考验,有报告表明能支持高达50 000个并发连接数,连接10 000个非活跃的HTTP keep-alive仅约占用2.5 MB内存。

3.3.2 Lighttpd

Lighttpd是一个德国人领导的开源软件,其根本的目的是提供一个专门针对高性能网站,安全、快速、兼容性好并且灵活的Web server环境。具有非常低的内存开销,cpu占用率低,效能好,以及丰富的模块等特点。

Lighttpd是众多开源的轻量级的Web server中较为优秀的一个。支持FastCGI,CGI,Auth,输出压缩(output compress),URL重写,Alias等重要功能,而Apache之所以流行,很大程度也是因为功能丰富,在Lighttpd上很多功能都有相应的实现了,这点对于apache的用户是非常重要的,因为迁移到Lighttpd就必须面对这些问题。

apache主要问题是密集并发下,不断的fork()和切换,以及较高的内存占用,使系统的资源几尽枯竭。而Lighttpd采用了Multiplex技术,代码经过优化,体积非常小,资源占用很低,而且反应速度相当快。

4 结束语

随着网络用户终端数量的不断膨胀和用户交互的增加,越来越多的网站和应用会遇到高并发问题。使用epoll和kqueue的异步I/O方式是目前解决这些问题的最佳方案。Web应用开发时考虑选择一个高性能的开发框架,可以在后期减少很多问题。如果并发连接数量很大,可以使用Nginx等高性能的Web服务器作为前端代理,来替代Apache的工作,得到更好的效果。

摘要:介绍了目前互联网服务器面临的C10K以及C500K问题,通过与传统的I/O模式进行比较,重点围绕Unix操作系统下新的异步I/O内核epoll和kqueue及其在Web服务开发和部署中的应用,研究了目前异步I/O实现高性能服务器的解决方案,为Web服务器应对大规模并发连接提出一个完整的方案。

关键词:异步I/O,高并发,Web服务器

I/O服务器 篇2

带有I/O模块和处理器的导轨被称为本地I/O导轨;带有I/O模块、电源、远程I/O通信卡并且安装在远离本地I/O导轨的导轨被称为远程I/O导轨。远程I/O导轨的`数目取决于不同处理器能够控制变量的数目。

远程I/O导轨与处理器之间的通信可以采用多种方式实现,具体包括同轴电缆、双轴电缆、屏蔽双绞线等,如果距离较远而需要考虑抑制噪声干扰问题可以采用光纤通信。

并行I/O模块:

并行I/O模块承担了与外部系统进行信息和数据交互的重要责任,可以用于扩展外围器件,者直接动键盘、LED等简单外部设备。

通常来说,51单片机有4个8位的并行I/O口,分别为P0、PI、P2、P3四组,其中PO和P2既可以用作普通I/O端口也可以当成数据地址端口,P3则在作为普通I/O端口的同时还具有其他(第二)功能,只有PI仅仪用作普通I/O口。

I/O服务器 篇3

电机温度是电机运行的一项重要参数, 主要包括电机定子温度和电机轴承温度。传统测量电机温度的方法主要有两种, 即采用PLC热电阻模块测量和采用温度变送器测量, 这两种方法均不同程度地存在一些缺点。

智能以太网I/O服务器采用先进的设计理念, 可将多种形式的输入信号转换为以太网信号上传, 以太网信号传输介质支持双绞线和光纤。信号输入类型包括DI、AI、AO、热电偶、热电阻等。智能以太网I/O服务器同时可执行输出DO、AO等输出信号。Jet I/O 6512 服务器是一款热电阻输入服务器, 支持两线、三线、四线制的接线方式, 对温度的测量范围较宽, 可分段满足被测对象的温度监测要求。

1 采用PLC热电阻模块测温法

采用PLC热电阻测温模块测量一个温度变量的系统结构见图1。该方法的优点是系统简单, 将每个被测量的pt100热电阻通过电缆接至PLC热电阻模块即可测量。但该法存在以下缺点:

(1) 热电阻输入的PLC模块价格较贵, 一个常用的6通道RTD测温模块价格约10 000元;

(2) 为提高测量精度, 每个pt100热电阻需要3芯电缆。以1台电机为例, 正常需测量8个温度量 (6个定子温度, 2个轴承温度) , 如果设备距离较远, 且测量电机较多, 则用电缆敷设不经济。表1为采用热电阻PLC模块测量电机温度参数的主要元器件价格。

2 采用温度变送器测量

采用开关量输出的温度变送器测量一个温度变量的系统结构如图2所示。温度变送器将被测量的pt100热电阻参数转换为模拟量输出或数字量输出。如果变送器采用模拟量输出, 其输出信号再接入PLC的模拟量输入模块, 则系统繁琐, 可直接采用第一种方法;如果温度变送器采用数字量输出, 由表2所示的主要元器件和价格统计情况可知, 选用此种方法有一定的经济优势, 但得不到连续的温度量。电缆用量也没有减少。

3 采用智能以太网I/O服务器测量电机温度

忻州神达能源集团原平选煤化工有限公司500万t选煤厂采用了智能以太网I/O服务器测量电机温度变量, 系统结构示意如图3。采用该技术可把热电阻智能以太网服务器设置在被测电机附近, 减少由热电阻至测温模块之间的长度, 然后通过光纤上传至集控室。表3为采用智能以太网服务器测量电机温度所需主要元器件和价格。在涡北选煤厂等新建选煤厂中, 测量电机温度也采用此种方法。

4 结 论

从三种电机温度测量方法的对比可知, 所测电机数量越多、电机越集中, 采用智能以太网I/O服务器的经济优势和性能优势越明显。另外从控制电缆的用量来看, 前两种方案的控制电缆长度是从电机至控制柜的距离, 采用第三种方案所用的电缆长度为从电机至附近控制箱距离, 控制箱至上级系统仅通过光纤或双绞线连接。由此可见, 控制电缆量会显著减少, 节省了大量电缆的采购和敷设费用。

在有些控制系统比较完善的选煤厂中, 各类测量控制装置也需用到以太网光纤作为通讯介质。本系统和其他系统可共用传输介质和路由器等设备, 从而可将不同控制系统合并, 达到简化选煤厂整体控制系统结构、节省成本的目的。

综上所述, 智能以太网I/O服务器在测量电机温度方面有一定技术优势, 随着产品性能不断提升以及产品价格的逐渐降低, 该方法在选煤厂的应用前景广阔。

参考文献

[1]王廷尧.以太网技术与应用[M].北京:人民邮电出版社, 2005.

[2]徐国林.PLC应用技术[M].北京:机械工业出版社, 2007.

[3]商海峰.基于工业以太网与现场总线的选煤厂综合自动化系统的设计[J].煤炭加工与综合利用, 2010 (6) :25-28.

[4]杨渊, 宗世棠.工业智能以太网I/O服务器在选煤厂的应用[J].煤炭加工与综合利用, 2011 (6) :34-36.

[5]成举炳.选煤厂低压电气数据采集系统[J].煤炭加工与综合利用, 2012 (2) :30-31.

关于I/O模拟的讨论 篇4

多年以来,Windows都为这种机制而引以为豪,其实在Windows下,有这样的一个原则,硬件例如CPU最好是一直工作的,这样才能得到更加充分的利用,而在Windows下,程序都是以进程形式获得在CPU这类的硬件中执行的机会,而作为轻量级的进程,执行资源的实际获得者线程的角度上看,就是要让线程不要停下来,需要让各个线程就它们正在执行的操作进行相互的通信,Microsoft在这个领域进行了数十年的研究和测试,终于开发了这种机制,叫做I/O完成端口(I/O completion port),通过这种机制,就可以让线程在读取设备或写入设备的时候不必挂起等待设备的响应,从而很大程度上提高了吞吐量,实现了计算机性能的巨大提升,如图1所示。

首先分析一下Windows的消息机制,只有了解了Windows的消息机制才能明白,什么是消息,Windows下利用上述的I/O机制,实现了线程与I/O之间的交互不必需要线程的挂起,但是消息产生到接收又是怎么解决的呢?Windows感知到有I/O的操作以后,会将该消息进行封装成为struct tagMSG(详细内容请查阅MSDN),这个结构体中将包含消息的类型,参数,时间,位置,和传递的对象。Windows将该消息投入到Windows消息队列,然后等待应用程序从队列中提取相对应的消息,在这里要明确几个问题,便是模拟I/O的层次问题和模拟的关键是什么?正如图1表达的,模拟可以在驱动级,系统级,或者用户级3个级别上进行,关键就在于模拟的何种消息、何时、何位置、发送给那些应用程序,这就成为了I/O模拟的关键所在。

2 用户级I/O模拟

正如图1所示,从消息队列到指定应用程序的这一段路径上的I/O模拟,便是用户级模拟,用户级模拟的特点是:

(1)通过Windows消息机制,并由系统发出,给指定的应用程序。

(2)指定的应用程序通过自己的窗口句柄等标识,从消息队列中获取消息。

这一部分的模拟需要用到Windows API,首先了解到在Windows下的应用程序,都会拥有一个自己的窗口句柄,这如同一个ID一样,指向了某一个窗口程序,就通过获取到指定应用程序的句柄,然后发送特定消息,这如何来实现呢,分享一段模拟代码:

这里就不再赘述一些细节了,但是需要注意的是,在FindWindowsEx中的第二参数,解决一些存在父子窗口的情况,通过对子窗口的句柄,有点类似线程ID了,就可以向指定线程发送消息,按键的消息需要延迟200毫秒,这是因为正常人的点击操作便是200毫秒,这样首先可以避免写入消息队列过快,造成溢出,也可以满足一些需要一定按键时长程序的特殊要求。这里的PostMessage函数有时可以用SendMessage函数替代,本身参数上没有区别,但是核心在于如果使用的是PostMessage那么发出消息后,模拟程序是不会理会该消息的处理的,但是使用SendMessage的话,应用程序就会一直等待该消息被正确处理的反馈,这样会一定程度上影响模拟程序的正常运行,因此建议使用PostMessage函数。其次Windows的消息叫做Windows_Message,这类消息共有1024(0x0400),所以可以设置高于1024的自定义消息。这样就可以模拟很多Windows下无法模拟的I/O消息,但是弊端就是要为自定义消息编写处理函数。

3 系统级I/O模拟

这一部分分析操作系统到消息队列这一段路径上的I/O模拟,这一段的模拟所具有的特点是:

(1)系统并不指定发送的对象,接受消息的进程为当前的活动进程。

(2)接收消息的程序可以发生改变,换句话说是可以存在进程间切换的。

首先分析一下正常情况下键盘消息的产生过程,这好比要完成对某一好友的问候,那么应当先选中一个好友,然后对他发送你好的消息,这一过程就是平时使用鼠标点击选中当前活动进程,或是用键盘切换选择活动进程的过程。这一部分的模拟通过Windows API也是可以实现的,下面我们分享一段模拟代码:

键盘消息的模拟,需要讨论的是虚键码MapVirtualKey函数,这个函数把逻辑上的‘U’键转换成计算机可以识别的二进制虚键码,可以不使用这个函数,但是效果就是模拟出的键盘消息不会被一些DirectX类游戏所接受,鼠标事件的模拟就要显得相对复杂了,因为不仅要产生事件消息,还要产生位置消息,这里的案例是对640*480窗口向全屏的鼠标坐标转换,有点类似窗口压缩的意思,需要解释的是对于一些DirectX类的射击游戏的鼠标模拟,这套方案并不是首选方案,其原因会在下面的驱动级模拟中详细给大家分析。

4 驱动级I/O模拟

这一部分要分析从驱动到操作系统和一种特殊的消息传递方式,在这之前,先要了解这样一个事实,在应用程序中有一类游戏应用程序叫做DirectX类游戏,比如冰封王座,CS,街霸,铁拳等,这类游戏的一个共同特征是:

(1)需要很高的即时操作要求,而且操作频繁。

(2)不使用Windows的消息机制,而是与驱动直接交互。

首先为了很好的人机交互感,这类游戏都会将操作精确到毫秒级,而且会产生大量的操作,这就要求对I/O缓存的一定使用要求,其次为了实现这类游戏的即时要求,这类游戏都会选择绕过Windows消息机制,因为通过Windows消息机制至少都有数百毫秒的延时,这难以满足游戏的需要,为此目的,这类游戏会选择直接与驱动进行交互,来接受I/O的操作。在这个层面的模拟就会显得比较复杂,而且Windows的API就不太好用了。

因此在这个层面的I/O模拟有两种设计方案,一种是需要重写某些I/O设备的驱动,这是比较麻烦的,还有一种方法是将消息写入某个特定的驱动然后产生相应的消息,下面着重分享一下第二种方法,写入驱动程序:

使用写入驱动的接口是WinI/O提供的,通过WinI/O就可以和驱动进行一定程度上的交互,分析一下这几段关键性代码:首先KBCWait4IBE()函数是用来检测驱动的缓存是否为空的,因为开始讨论到,如果模拟的消息过平凡地投递到驱动,那么消息就会出现一定程度上的溢出,这样的话,很多的操作就会出现丢失,这样是很不好的,所以每当要将内容写入到驱动的时候,都要检测一下是否驱动的缓存已经满了,这并不会造成严重的延迟,但是对一些组合操作来讲,丢失一个操作就有可能丢失了一批操作,所以在驱动级模拟I/O的操作关键就在于避免缓存溢出。此外,MY_KEY_DOWN&MY_KEY_UP是相类似的,将差异分析一下,首先,要产生的按键的ASCII码转换为虚键码,然后等待缓存,当可以写入的时候首先要发送一个命令消息0xD2,即为写入缓存,然后得到写入的权限后写入一个数据0xE2,告诉驱动要写入的是一个键盘消息,然后等待缓存,写入要写入消息的虚键码,于是消息被写入,但是这个时候键盘消息是按下消息,如何将其按起呢?使用0x80也就是标识当前某一按键被取消的标识位,当这一位被标识后,按键消息就变成了按键取消消息,从而从键盘上驱动模拟发出这一消息。

5 结语

详细介绍了在用户级、系统级和驱动级实现对I/O设备的模拟操作,分享了Windows API编程、WinIO驱动编程的案例。也详细地分析了Windows消息机制的优缺之处和如何利用和脱离Windows消息机制。

摘要:详细分析Windows的I/O机制,提出了分别在用户级、系统级、驱动级的I/O模拟操作,通过实际案例和源代码分享在I/O模拟上的得失,着重介绍鼠标与键盘的模拟。

关键词:I/O机制,I/O模拟

参考文献

对象I/O技术的模拟实现 篇5

我们知道C++对象是“存活”在RAM中的,由于RAM的易失性[1],程序需要将对象存入磁盘中,将来需要时再把对象读入内存加以恢复,这样一来就好像对象一直“活”着一样,因此对象的持久化是C++中的一个非常重要的操作。

许多程序员可能有这样的误区,利用下面的代码:saveClassName();className=readClassName();p=new className;不就轻松实现对象的保存和恢复了吗?

需要指出的是,在C++中,是通过new A而非new“A”(或className=“A”,new className)实例化A的对象。换句话说,试图利用下面的代码className=readClassName();p=new className;来达到通过类的字符串名称动态创建对象的做法是根本行不通的,因为p=new className根本无法通过编译![2]

由此我们得出对象的持久化需要的两个条件:

(1)获取对象所属类的名称的能力;

(2)能根据类的字符串名字动态创建对象的能力。

这两种能力的获得目前有两种解决方案:

一是由C++编译器(compiler)提供———例如Borland C++4.5:

二是由程序员自己加上去。

本文是通过第二种方法模拟实现对象的持久化机制,从而深入探讨了对象I/O技术的实现机制。

本文结构如下,首先描述了对象持久化的实现,其次对实现进行了验证,最后是论文进行总结。

1 对象持久化的实现

为了说明问题而又不失一般性,我们假定有三个类,分别是Object,A和B,其中A和B都派生于Object,类的定义如下:

为了让对象具备持久化的两个条件,需要依次为对象添加如下信息。

1.1 为每个类增加对象创建函数CreatObject,如表2所示。

1.2 增加类的识别信息(类名称或ID等)以及继承信息,由于这部分信息比较多,可以将其整合到一个结构体Struct ClassInfo中。ClassInfo中保存有两个链表:

类的继承链表和程序中所有类的类型信息链表。类的识别能力就由这两个链表来完成。换句话说,我们希望在main函数执行之前内存中就存在如图1所示的两个链表。其中类的继承链表是由Struct ClassInfo的带参构造函数完成的(在VC++中,结构体也可以有构造函数),而类的类型信息链表则是由ClassInfoInit类完成的。Struct ClassInfo和ClassInfoInit的定义如表3所示。注意,链表的创建是在它们的构造函数中完成的。

最后一步,将类型信息作为类的静态的成员变量添加进来,并为每个类实例化静态的初始化类,目的是在main函数执行之前得到图1所示的两个链表。

在这要强调一下static关键字的作用:

(1)如果类的成员变量被Static关键字所修饰,则这该属性不是为类中的每个对象分别拥有,而是共用,其引用形式不是对象成员变量,而是类成员变量,即不需要市里实例化对象就可以使用。成员函数也与此相仿[3]。

(2)如果对象(包括作为类成员的对象),如initObject、ObjectInfo等,被说明为Static,则这些对象是在main函数执行之前就已经存在了,换句话说,这些对象的构造函数是在main函数调用之前就已经被调用了。因此在main函数执行之前,内存中就已经存在着图1所示的链表就可以理解了。

我们添加的RTTI信息能否有效的支持对象的持久化可以由试验来验证。

2 试验

该试验主要验证了对象持久化必须具备的两个能力,即动态创建对象能力和获取对象所属类的能力。试验的环境如下:操作系统Windows XP sp2,IDE环境是VC++6.0 SP6。如需要全部源代码可与作者联系(hehh6@henu.edu.cn)。

通过对象增加的RTTI信息(增加的静态成员变量),获取对象所属类的能力自然具备。

动态创建对象能力实际上就是根据类的字符串名称来实例化对象的能力,在图1所示链表的支持下,该功能可以非常轻松的实现。

思路如下:通过ClassInfo::pFirstClass查找类名匹配的ClassInfo,利用ClassInfo中的pCreateObject指针实例化对象,为方便起见,可为程序增加查找函数

3 结束语

本文在手动添加的RTTI信息的支持下实现了对象的持久化,从中读者可以深入了解对象持久化的的实现机制。

在商业的编译器VC++中其实现持久化是通过一个神秘的宏,当将该宏展开后,VC++实现持久化的的思路和本文大同小异,只是更精巧[4]。

参考文献

[1]Stanley B.Lippman.Inside The C++Object Model(深度探索C++对象模型)[M].侯捷,译.武汉:华中科技大学出版社,2001.

[2]葛磊.The Object's Permanence Technology and Its Realization in MFC[J].开封大学学报,2006,20(1).

[3]钱能.C++程序设计教程[M].第二版.北京:清华大学出版社,2005:418-419.

远程I/O系统在罐区的应用 篇6

关键词:远程I/O,通信,DCS

0 引言

金陵石化芳烃部中间罐区仪表采用远程RTU接入DCS方式, 现场检测、报警仪表的信号接入远程I/O单元, 由远程I/O单元转换成通信信号, 连接至相应的DCS系统, 控制仪表及可燃气有毒气检测仪表采用电缆直连至相应的DCS系统。

现场每套远程I/O系统输出两路Modbus信号, 分别进入两个不同装置的DCS系统, 一路进PX装置, 另一路进3重整装置。

1 远程I/O系统

模块化的远程I/O系统通过总线接口将现场二进制和模拟量的传感器和执行器连接至控制系统, 传输安全区域或者爆炸危险区域的现场过程数据。远程I/O系统可连接设备:流量变送器、阀门定位器、压力传感器或者温度变送器、热电偶 (TCs) 、电阻式温度检测器 (RTDs) 、机械触点以及声光报警器等。远程I/O系统兼容Profibus-DP、Modbus-RTU、Modbus TCP/IP和Foundation Fieldbus等网络协议。远程I/O适用于爆炸危险区或者严酷工业环境, 例如海洋平台和户外。典型的应用行业包括石油天然气 (内陆及海洋) 、制药、化工、污水处理、食品饮料等。

远程I/O系统具备高适应性和操作简单的特征。系统安装在现场设备侧, 仅需一根总线电缆即可连接远程I/O系统到DCS, 能够减少接线, 还能够节省时间、节约成本和减少工作量。

P+F公司的LB系列远程I/O具备危险区2区认证, 可安装在Zone 2、Class I、Div.2或者非危险区域。该模块化的信号调节系统将现场信号关联至非危险区域的控制系统, 连接方式有安全区域现场连接 (NonEx) 和本质安全区域现场连接 (Ex i) 。

金陵石化公司芳烃部新建中间罐区正是采用LB系列的远程I/O系统, 如图1所示。

该系统的底板结构如图2所示。X4为现场总线接口, 用来与DCS通信, 现场实际用于与PX通信;X5为冗余现场总线接口, 用来与DCS通信, 现场实际用于与#3重整通信;X6为服务总线, 用于连接PC机进行相应的组态;X7为扩展机架接口;CHANNEL1/2为通信模块;CHANNEL3-24为I/O卡件;POWER1-3插槽为插相应的供电模块。

2 远程I/O系统的组态过程

(1) 打开PACTWARE, 添加设备, 如图3所示。

(2) 选择添加相应的LB系统, 选择好相应的COM口后选择SCAN SERVICE BUS, 自动扫描网关设备, 如图4所示。

(3) 按照设计图纸在每个通道插入相应的插件, 然后进行具体的点组态, 如图5所示。

(4) 在实际的组态中, 为了通信方便, 处理量程统一设置成0~4095。为了能够与TPS系统通信, 必须对相应的Modbus地址进行分配, 如图6所示。点击Auto marshalling按钮, 系统会自动根据卡件的通道号分配相应的地址。组态结束后, 对相应的系统进行下载。

3 与DCS通信

LB远程I/O系统与Honeywell TPS系统采用的是标准的Modbus-RTU通信协议。

控制器和主机为主从关系。仅一设备 (主设备) 能初始化传输 (查询) , 其它设备 (从设备) 根据主设备查询提供的数据做出相应反应。这种传输方式也使得信号在Modbus网络中的通信井然有序。

根据系统的特点, 采用RS-485接口, 接口采用平衡驱动器和差分接收器的组合, 使用屏蔽双绞线传输 (一般只需二根连线) 数据, 抗共模干扰能力增强, 抗噪声干扰性好。

将现场远程I/O系统的通信线连接DCS中的SI卡FTA板, 在DCS中组态相应的ARRAY点, 设置地址、波特率、通信协议, 分别如图7、图8、图9所示。

建立相应的通信之后, 要对模拟量点的量程进行转换, 以达到实际使用要求。

4 结语

远程I/O系统不但节省成本, 减少工作量, 而且可以在线对参数进行修改, 在线监测功能强大, 利于故障的判断, 减少了维护量。

参考文献

[1]丁宝苍.过程控制系统与装置[M].重庆:重庆大学出版社, 2013

[2]乐嘉谦.仪表工手册[M].北京:化学工业出版社, 2003

[3]厉玉鸣.化工仪表及自动化[M].北京:化学工业出版社, 2011

[4]张春华, 肖体兵, 李迪.工程测试技术基础[M].北京:机械工业出版社, 2011

[5]王树青, 乐嘉谦.自动化与仪表工程师手册[M].北京:化学工业出版社, 2010

[6]武平丽, 高国光.过程控制工程实施[M].北京:电子工业出版社, 2011

CC2530普通I/O口的扩展 篇7

1 CC2530的I/O口扩展方法的总体思路及各组成工作原理

1.1 CC2530的I/O口扩展方法的总体思路

本扩展方法采用CC2530的I/O口模拟IIC总线的SCL和SDA, 通过IIC总线控制PCA9554芯片, 使串行通信变成并行通信。从理论上来讲CC2530芯片P1口的8个I/O口就可以连接4组IIC通信, 每组因扩展芯片地址A2A1A0的不同可同时支持8个芯片, 每个芯片又可控制8个端口。因此, CC2530的P1口从理论上就可支持128个 (4×8×8) 端口, 如图1所示。并且, 如果芯片固定的头地址不一样的话, 例如PCA9554和PCA9554A, 那么端口数量又可增加一倍, 这样P1口就扩展成了256个端。依此类推CC2530的I/O口通过扩展数量呈几十倍的增加, 可大大丰富I/O口的应用。

1.2 IIC总线工作原理

IIC总线只有两条线, 一条是数据线SDA, 另一条是时钟线SCL。数据线SDA在时钟线SCL的控制下可串行发送和接收数据, 传送速率最高达100kbps。各被控制器件均并联在这两条线上, 每个接到IIC总线上的器件都有唯一的地址, 通过不同地址决定通信对象, 如图1所示。这样, 各控制电路虽然挂在同一条总线上, 却彼此独立, 互不相关。IIC总线的优点是占用的空间非常小, 可避免线路互连而使电路板走线错综复杂的现象, 减少了电路板上的布线空间, 降低了互联成本。

IIC总线上只有四种信号:开始信号、停止信号、重新开始信号和应答信号。IIC总线上能实现主/从双向通讯, 器件发送数据到总线上, 则定义为发送器, 器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态。IIC总线时序如图2所示。

1.3 PCA9554工作原理

PCA9554是带中断的GPIO扩展芯片, 它提供了IIC总线方式应用中的8位串行转并行输入/输出口的扩展。PCA9554共有4条命令, 在总线主控制器 (本文中为CC2530) 向PCA9554发送写数据过程中, 命令字节是紧跟地址字节, 之后第一个字节作为一个指针指向要进行写或读操作的寄存器。CC2530通过总线写I/O口的相应配置位来激活端口的输入或输出。通过给PCA9554的A2A1A03个管脚不同的电平来实现不同IIC地址, A2A1A03个管脚可组成8个地址码, 由此总线上最多允许挂8个PCA9554。而PCA9554与PCA9554A的IIC固定地址不同 (PCA9554的固定地址为01000A2A1A0, PCA9554的固定地址为01110A2A1A0) , 这样就允许16个器件 (PCA9554和PCA9554A各8个) 连接到同一个IIC总线上, 每个器件扩展出8个I/O端口, 这样CC2530的两个I/O端口就可扩展到8x16个I/O口。

2 扩展I/O口的应用

本应用通过CC2530的I/O口 (P1.0和P1.1) 模拟IIC总线的SCL和SDA, 然后通过IIC总线形式控制GPIO扩展芯片PCA9554, 最后通过扩展的IO来控制LED、蜂鸣器、按键信号、继电器等, 如图3、4所示。

3 结语

本文通过IIC总线形式控制GPIO扩展芯片PCA9554扩展CC2530的I/O口。在文主要提出了具体的硬件设计, 并运用于实践中。CC2530的I/O口进行扩展, 使I/O口的数量大大增多, 能丰富开发设计者的运用。

参考文献

[1]施邦平.采用I2C器件扩展单片机的多级通信[J].自动化与仪器仪表, 自动化与仪器仪表, 2006 (6) :63-64.

I/O服务器 篇8

关键词:I/O性能,流,缓冲区,分配和回收

Java应用程序都会经常使用java.io包, 例如磁盘文件读写和通过网络传输数据。然而初学者由于对java.io包的理解的局限性导致编写的程序I/O性能很差。所幸的是, 只要对java.io包有了很好的理解, 就可以杜绝这方面的问题, 从而保证程序拥有较好的I/O性能。

本文首先对java.io包做一个简要的介绍, 然后指出导致I/O性能低下的根本原因是没有采用缓冲机制, 然后循序渐进地采取了三种策略, 将I/O性能逐步提高到168倍, 这三种策略分别是采用缓冲流, 定制自己的缓冲区, 定制静态的固定长度的缓冲区。

1 I/O操作的基本概念

在Java I/O中最基本的概念是流 (Stream) , 流是一个连续的字节序列, 包括输入流和输出流, 输入流用来读取这个序列, 而输出流则用来写这个序列, 在默认情况下Java的流操作是基于字节的, 即一次只读或只写一个字节。

java.io包提供了Input Stream和Output Stream作为对I/O操作的抽象, 这两个接口决定了类层次结构的基本格局。Input Stream和Output Stream的具体实现类提供了对不同数据源的访问, 如磁盘文件和网络连接。

java.io包还提供了过滤流 (Filter Stream) , 过滤流并不指向具体的数据源, 而是在其他流之上进行了包装, 这些过滤流其实是java.io包的核心。从性能的角度来看, 最重要的过滤流是缓冲流 (Buffered Stream) , 图1显示了一个简化的类层次结构图。

2 缓冲流

导致I/O性能低下的主要原因是没有对I/O操作进行缓冲。众所周知, 硬盘擅长于大块数据的读写, 但是在小量数据的读写上性能不好, 所以, 为了最大化I/O性能, 我们应该选择批量的数据操作, 而缓冲流正是为这个目的设计的。缓冲流, 包括Buffered Input Stream和Buffered Output Stream, 它为I/O流增加了内存缓冲区, 使得Java程序一次可以向底层设备写入或者读取大量数据, 从而提高了程序的性能。

为了更好地理解缓冲流的效果, 请阅读程序清单一, 这个例子采用了原始的文件流实现文件的拷贝。copy方法打开了一个File Input Stream和一个File Output Stream, 并将数据从一个流直接拷贝到另一个流。由于read和write方法是基于字节的, 所以实际的磁盘读写也是按字节发生的。实践证明使用这段代码拷贝一个8M的文本文件需要花费36750ms。

程序清单一中的copy方法只需稍作修改就能有效地改善性能, 如程序清单二所示, 它在原始的文件流之上采用了缓冲流Buffered Input Stream和Buffered Output Stream, 缓冲流将每一个小的读写请求积攒起来, 然后一次性地批处理, 通常是将几千个读写请求合并成一个大的请求。改进后的copy方法拷贝一个8M的文本文件需要花费1187ms, 性能大约提高了31倍。

3 建立自己的缓冲

缓冲流虽然在它的内部增加了内存缓冲区, 使得在缓冲区和底层设备之间写入或读取大量数据成为可能[2,3], 但是在这之上Java程序仍旧使用while循环从该流 (实际上是缓冲数组) 按字节读写数据。由于缓冲数组的大小是一定的, JVM需要针对数组做越界检查, 该操作会导致额外的系统开销。另一方面, 为了支持多线程环境, 将数据从Buffered Input Stream的缓冲数组拷贝到Buffered Output Stream的缓冲数组, 其中的方法调用很多都是synchronized, 这也会导致额外的系统开销。所以尽管程序清单二所示代码可以有效地改善性能, 但是改善的程度仍然不尽人意。

还是利用硬盘擅长读写大块数据这一特性, 我们可以自己建立缓冲, 以避免上述额外的系统开销。这需要使用Input Stream和Output Stream提供的两个重载方法, 它们允许按字节读写, 也可以按字节数组读写, 如下所示:

程序清单三创建了自己的缓冲区, 即字节数组byte[]buffer, 其大小是整个文件的字节长度, 然后将整个文件一次性读入内存, 再一次性写到另一个文件。这个代码非常快, 拷贝一个8M的文本文件所花费时间降低到750ms。

注意, 使用这个策略需要权衡两个因素。首先是缓冲区的大小, 它所创建的缓冲区的大小等于被拷贝的文件大小, 当文件很大时, 该缓冲区也会很大。第二, 它为每次文件拷贝操作都要创建一个新的缓冲区, 当有大量文件需要拷贝时, JVM不得不分配和回收这些大缓冲区内存, 这对程序性能是极大的伤害。

如何在保持速度甚至速度更快的前提下避免这两个缺陷呢?方法是这样的:创建一个静态的固定长度的字节数组, 如1024*1024字节即1M, 每次只读写1M的数据。虽然对于大于1M的文件会需要多次读写才能完成整个文件的拷贝, 但是这样避免了内存的反复分配和回收。缓冲区大小是可以调整的, 针对某个具体的应用场景, 我们可以在速度和内存之间取得一个最佳的平衡。

程序清单四的copy方法使用了这样的1M字节的数组, 这个版本表现更为出色, 它拷贝一个8M的文本文件所花费时间只有218ms, 性能提高了168倍。

值得注意的是代码中的同步块, 在单线程环境下没有同步块是可以的, 但是在多线程环境下需要同步块防止多个线程同时对缓冲区实施写操作。尽管同步会带来系统开销, 但是由于while循环的次数很小 (8M文件只要循环8次) , 所以由此带来的性能损失是可以忽略不计的。实验证明, 有同步块的版本和去掉同步块的版本, 性能是一样的。

下表显示了采取四种不同的策略拷贝一个8M文件所花费的时间。它充分说明, 有效地改进缓冲机制可以大大提高程序的I/O性能。

4 结束语

一般情况下, 我们总可以为具体的应用程序找到改善I/O性能的方法, 这需要具体分析该应用程序的目的和操作特性。例如, 考虑FTP和Http服务器, 这些服务器的主要工作就是将文件从磁盘拷贝到网络的Socket, 一个网站的主页通常比其他网页访问得更多。为了提高性能, 我们可以建立快速缓冲贮存区, 将那些经常被访问的文件做缓存, 这样这些文件就不必每次从磁盘读写, 而是直接从内存拷贝到网络。

参考文献

[1]What is Java I/O?[EB/OL], http://www.roseindia.net/java/example/java/io/Java_io.shtml

[2]Buffered Input Stream, JavaTM Platform Standard Ed.7[EB/OL], http://docs.oracle.com/javase/7/docs/api/java/io/Buffered Input Stream.html

上一篇:慢性髓细胞下一篇:呼吸门控系统