IOCP

2024-08-01

IOCP(共5篇)

IOCP 篇1

1 背景

随着计算机技术, 尤其是网络技术的飞速发展, 如今的程序员不仅仅局限于基于单机运行或单一线程的应用程序的开发。C/S模式的最显著的特点是一个服务器端能同时为多个客户提供服务。而传统的C/S模式通常为每一个客户创建一个独立的线程, 这种实现方式在客户端数量不多的情况下问题不大, 但对于类似于铁路网络订票这样的瞬间客户数量巨大的系统来说, 效率极端低下。这是因为一方面创建新线程的开销较大, 另一方面同时有许多线程处于运行状态, 操作系统内核需要花费大量时间进行上下文切换, 并没有在线程执行上花更多的时间。因此, 微软在Winsocket2中引入了IOCP (Input/Output Completion Port, I/O完成端口) 模型[1]。

2 基本概念

所谓同步, 就是在发出一个功能调用时, 在没有得到结果之前, 该调用就不返回。按照这个定义, 其实绝大多数函数或方法都是同步调用。

异步的概念和同步相对。当一个异步过程调用发出后, 调用者不能立刻得到结果。实际处理这个调用的部件在完成后, 通过状态、通知和回调来通知调用者[2]。

通俗来讲, 完成一件事再去做另外一件事就是同步, 而一起做两件或者两件以上的事情就是异步了。下面通过一个服务器与客户端通信的例子来说明这两个概念。

如果是同步:Client发送一条请求消息给Server, Client就会等待Server处理该请求。这段时间内, Client只有等待, 直到收到Server回复的响应信息后, 才能发起第二条请求消息。这样无疑大大降低了系统的性能。

如果是异步:Client发送一条请求消息给Server后, 并不需要等待Server的处理结果, 而是可以继续发送第二条甚至更多的请求消息。Server会将这些请求都存入队列, 逐条处理, 并将处理完的结果回复给Client。这样一来, Client就可以不用等待, 效率得到大大提高。

阻塞调用是指调用结果返回之前, 当前线程会被挂起, 函数或方法只有在得到结果之后才会返回。阻塞和同步有点类似, 但是同步调用的时候线程还是处于激活状态, 而阻塞时线程会被挂起。

非阻塞调用和阻塞的概念相对应, 指在不能立刻得到结果之前, 该函数或方法不会阻塞当前线程而是立刻返回。

下面给出一段常见的基础代码:

只要写过网络程序的朋友, 对这样的结构都应该相当熟悉。Accept后线程被挂起, 等待一个客户发出请求, 而后创建新线程来处理请求。当新线程处理客户请求时, 起初的线程循环回去等待另外的客户请求。在这个并发模型中, 对每个客户都创建了一个线程。其优点在于等待请求的线程只需要做很少的工作, 而大部分的时间都处于休眠状态。但是创建线程的开销远远大于程序员的预计, 尤其是在并发量巨大的情况下, 这种传统的并发模型效率极端低下。解决这个问题的方法之一就是IOCP[3]。

3 IOCP的概念与实现

简单来说, IOCP是一种高性能的I/O模型, 是一种应用系统使用线程池处理异步I/O请求的机制。Java7中对IOCP有了很好的封装, 程序员可以非常方便地通过封装的channel类来读写和传输数据。

下面介绍IOCP模型的实现。首先我们创建一个完成端口Create IOCompletion Port;然后再创建一个或多个工作线程, 并指定它们到这个完成端口上读取数据;再将远程连接的套接字句柄关联到这个完成端口, 工作线程调用get Queued Completion Status方法在关联到这个完成端口上的所有套接字上等待I/O的完成;再判断完成了什么类型的I/O;接着发出WSASend和WSARecv, 并继续下一次循环阻塞在get Queued Completion Status。

具体来说, 一个完成端口大概的处理流程包括:

(1) 创建一个完成端口。

Port port=create Io Completion Port (IN-VALID_HANDLE_VALUE, 0, 0, fixed Thread Count () ) ;

(2) 创建一个线程Thread A。

(3) Thread A线程循环调用Get Queued Completion Status方法来得到I/O操作结果, 这个方法是一个阻塞方法。

(4) 主线程循环调用accept等待客户端连接上来。

(5) 主线程accept返回新连接建立以后, 把这个新的套接字句柄用Create Io Completion Port关联到完成端口, 然后发出一个异步的Read或者Write调用。因为是异步函数, Read/Write会马上返回, 实际的发送或者接收数据的操作由操作系统去做。

(6) 主线程继续下一次循环, 阻塞在accept这里等待客户端连接。

(7) 操作系统完成Read或者Write的操作, 把结果发送到完成端口。

(8) Thread A线程里的Get Queued CompletionStatus () 马上返回, 并从完成端口取得刚完成的Read/Write的结果。

(9) 在Thread A线程里对这些数据进行处理 (如果处理过程很耗时, 需要新开线程处理) , 然后接着发出Read/Write, 并继续下一次循环阻塞在Get Queued Completion Status () 这里。

4 Java中的异步I/O与IOCP

Java中的IOCP的实现与前文中所描述的实现思想基本相同, 唯一的区别是Java中封装了相关的内部实现。

Iocp类:该类使用默认的访问修饰符, 因此只能被同包 (sun.nio.ch) 的其他类访问。同时, 创建IOCP端口的create Io Completion Port方法被封装在Iocp类的构造函数中, 套接字的关联也不再需要调用create Io Completion Port而是直接调用Iocp类的associate方法。

Iocp.Completion Status类:Iocp的内部类Completion Status用于存取完成端口的状态信息。

Iocp.Event Handler Task类:Iocp的内部类Event Handler Task用来将I/O操作的Handle关联到完成端口, 循环地获取完成端口的状态, 根据操作系统返回的完成端口状态从任务队列中提取下一个要执行的任务并调用执行。

Iocp的调用类:sun.nio.ch包中的Windows Asynchronous Socket Channel Impl、Windows Asy nchronous Server Socket Channel Impl和Windows Asynchronous File Channel Impl等类使用了Iocp类的相关方法, 达到多并发量时的高性能I/O访问。

Native方法:Iocp类中的许多内部方法都是通过调用JNI方法实现的。

从上述介绍我们可以知道, Java7对IOCP进行了很好的封装。我们可以直接使用JDK中众多的Channel Impl类, 这些类的读写操作都应用了Iocp类。当然, 我们也可以将自定义的逻辑实现类放置在sun.nio.ch包中以重用Iocp类, 甚至还可以自己编写和实现Iocp类。下面我们通过一个日志传输的具体例子来看Iocp以及应用类在实际应用中的使用。

假定现有建立了连接的服务器端和客户端, 服务器端执行得到的日志信息需要传输到客户端的控制台中。这些信息的传输必须是异步的, 也就是说服务器端不等待传输的完成而是继续执行并产生更多的日志信息。同时, 日志信息在通道上传输的时候又必须是同步的, 这样才能保证日志信息的先后次序保持一致。

首先, 服务器端监听端口, 建立与客户端通信的通道。

服务器端主线程并不直接将日志信息通过通道输出到客户端的控制台上, 而是调用write Message方法将执行得到的日志信息写入事先准备好的message Queue里, 并继续业务逻辑的执行。

同时, 另一个线程负责不断从message Queue中读取日志信息, 按顺序写到通道上传输给客户端控制台。Write Completion Handler是Completion Handler接口的自定义实现类, 用来控制每次通道上的写操作, 使其必须完成后才能返回, 避免打乱输出的日志次序。

这样, 我们能很轻松地在网络应用中使用chan-nel Impl类, 而且如果深入到这些channel Impl类的内部, 我们会看到许多逻辑的实现都依赖于底层的sun.nio.ch.Iocp类。

5 结束语

本文从传统的C/S模型出发, 分析了传统的网络应用开发的弊端, 进而介绍了IOCP的基本概念, 比较IOCP与传统C/S模型的利弊, 分析了IOCP实现的基本步骤和Java中异步I/O和IOCP的具体实现, 并以一个日志处理的具体实例分析和介绍了IOCP思想在实践中的应用。

参考文献

[1]陈和平, 万敬麟.基于模块化结构和IOCP机制的文件在线更新方案[J].计算机应用, 2004, 24 (12z) :10-11, 14.

[2]李峰.基于Winsock的阻塞和非阻塞通信模型[J].电信交换, 2006, (02) :33-37.

[3]陈耿.一种串口通讯新模型的研究与应用[J].电脑知识与技术, 2013, 9 (04) :689-692, 706.

IOCP 篇2

北斗地基增强系统建成以后,数据播发平台将为全国用户提供高精度卫星定位服务,可接入的卫星差分定位终端也将达到数亿量级。随着北斗地基增强系统的不断推广,北斗差分定位用户数的不断增加,北斗数据播发平台未来必将面临同时处理百万级甚至千万级终端用户的并发访问。且根据播发服务的特点,用户与播发平台之间的连接大部分都为长连接。因此,播发系统在建设的过程中必然会面临高并发、长连接的大规模数据访问。

经典的多线程池模型为每一个客户端创造一个独立的线程, 随着请求服务的客户端数量的增加,服务器将要创建大量的线程,但是线程数量是有限制的,而且大量的线程之间的切换也浪费了许多的CPU时间,严重影响了系统的效率。为了解决这些问题,微软花了数年时间进行研究和测试的一种非常好的机制来支持这种服务,这种机制被称为IOCP。

1 IOCP模型

IOCP是一种使用线程池处理异步I/O请求的高性能I/O模型,它的基本架构如图1所示:

主要有三种类型的参与者:

完成端口:任何想利用IOCP方式来处理I/O请求的I/O设备,都必须把该IO设备的句柄关联到完成端口。完成端口维护是一个先进先出的I/O完成队列,操作系统把异步I/O操作完成事件通知放入该队列后,完成端口唤醒等待者线程队列中的一个工作线程对数据进行处理。

等待者线程队列:工作线程通过调用Get Queued Compleion S tatus API,在完成端口上等待取下一个I/O完成包。

执行者线程组:工作线程已经从完成端口上获得I/O完成包, 在占用CPU进行处理。

2 IOCP在北斗广域差分数据播发平台应用中存在的问题及解决方法

IOCP在实际应用于北斗广域差分数据播发平台时暴露出一些问题,下面详细介绍遇到的问题及恰当的解决方案。

2.1用户端信息的识别和提取

基于IOCP的播发平台在实际应用中将处理大量用户的I/O请求,在完成端口完成用户的I/O请求后,交给工作线程池中的一个空闲线程处理,这个工作线程必须知道这个完成的工作I/O请求来自哪个用户(该用户的Sockaddr_in结构数据和连接该用户的Socket),以及I/O数据存放位置(存放数据的缓冲)。

在IOCP中,工作线程通过调用Get Queued Completion Status函数从一个指定的完成端口中获取一个I/O完成包。这个函数带有两个具有扩展性的参数,一个是LPDWORD类型的参数lp Completion Key(完成健);另一个是OVERLAPPED类型的指针。其中完成健是一个套接字句柄关联完成端口时的一个参数, 在这里可以取出这个参数,这是一个指针类型的参数,我们可以通过扩展这个参数使其成为指向带有用户端地址信息的数据结。 这样我们在这里就可以通过完成健获得用户端信息,识别用户。

IOCP使用OVERLAPPED结构进行异步、非阻塞I/O,在基于IOCP的输入、输出操作时必须带有一个指向OVERLAPPED结构的指针参数。工作线程可以得到这个参数,但是通过这个参数不能确定I/O的操作类型(READ、WRITE、ACCEPT)。通过上面的分析,我们可以扩展OVERLAPPED结构,使其包含所需的操作类型等用户跟踪信息,这样我们在工作线程中利用CONTAINING_RECORD取出扩展的数据结构,就可以确定操作类型。

2.2数据包重排序

虽然IOCP是严格按照先进先出(Fist In First Out,FIFO) 处理I/O请求,但是,因为工作线程是多线程的,可能导致实际I/O请求的完成顺序不确定。例如三个工作线程A、B、C依次从完成端口取出“数据包1、数据包2、数据包3”,由于三个独立线程工作情况的不确定性,可能处理完的顺序是“数据包3、数据包1、数据包2”等各种情况。针对这个问题,通过对I/O内存增加顺序号,并按内存顺序号依次处理,对内存号不符合当前要处理的顺序号要求时,先将该I/O内存保存。

2.3系统内存资源管理

在基于IOCP的北斗广域差分数据播发平台中需要给每个合法的客户端连接分配一个内存空间,用于存储连接客户端的地址和SOCKET等信息(统称单句柄数据),当该连接断开时需要及时释放相应的内存资源。在北斗播发平台,大规模、高并发的用户请求将导致频繁的内存分配、释放,这种情况非常占用系统资源。针对这个问题,可以通过内存池的方法来解决,事先创建指定数量的单句柄数据内存块,然后将其全部放入一个空闲队列中,当有新的连接请求时,首先看空闲队列中是否还有可用的单句柄内存块:如果有,则将第一个可用的单句柄数据内存块取出使用;否则向系统申请一个单句柄数据内存块。在断开用户端连接,需要释放单句柄内存块时,首先判断空闲队列是否已满,如果未满,将单句柄内存块清空后存入队列;否则释放该内存块。

在播发平台中,需要高频率地接收、发送数据,每一次接收、 发送数据都要申请一块用于存放将要发送或接收的数据、数据长度、操作类型等(统称单I/O数据)内存块。这种情况也涉及到内存块的频繁分配与释放,也将造成系统资源的极大浪费。针对这个问题,我们可以采用单I/O数据内存池管理的方法来解决。

2.4多线程响应用户的连接

在典型的IOCP模型中,在主线程中调用阻塞的accept() 函数接受用户的连接,然后把新建的连接套接字绑定到完成端口。在基于IOCP的播发平台,使用单线程响应用户的连接请求, 无法满足大规模、高并发的用户访问需求。这个问题的解决方法是在主线程投递指定数量的异步、非阻塞的Accept Ex I/O请求, 利用IOCP机制在工作线程中处理用户连接请求,实现多线程并发处理用户连接请求,提高用户连接的响应速度。

3基于IOCP的北斗播发平台设计

3.1北斗播发平台的数据流

北斗播发平台的设计需要满足上亿注册用户、千万级同时在线用户的服务,这样大规模的用户量,单台服务器是不可能满足需求的。根据实际情况,这里打算采用服务器集群的方式来实现北斗播发平台,我们通过设计高性能的基于IOCP的单台北斗播发服务器,达到减少所需的服务器数量,降低整个系统的硬件成本目的。图2是北斗广域差分数据播发平台的数据流程图,这里我们专注研究北斗广域差分数据播发服务器的单台服务器性能。

3.2单台服务器的IOCP通信设计

3.2.1 IOCP的主要数据结构设计

(1)CIOCPBUFFER结构

该结构是对OVERLAPPED结构的扩展,其中n Sequence Nu mber字段用于数据包重排序;n Operatioon字段用于确定完成I/ O包的操作类型。

(2)CIOCPContext

为每一个新建立的用户分配一个CIOCPContext结构的内存块, addr Local字段保存连接的本地地址;addr Remote字段保存连接的远程地址,该字段用于用户端信息的识别;n Read Sequence 、 n Current Read Sequence、p Out Of Order Reads三个字段和CIOBUFFER的n Sequence Number字段共同作用完成数据包重排序。

3.2.2 IOCP的工作流程介绍

程序的工作流程如图3所示。

主线程首先程创建完成端口,然后创建侦听套接字并关联到完成端口,最后启动侦听线程。

侦听线程投递指定数量的接受I/O,创建指定数量的工作线程,创建事件数组,处理程序运行中的各种事件,工作线程通过get Quened Completion Status获取完成的I/O,针对不同类型的操作,调用相应的函数处理。

3基于IOCP的北斗播发平台测试

3.1测试环境

6台Intel(R)Core(TM)i5-2520M CPU ·2.5GHz 2.50GHz 4G内存笔记本6台。一台作为服务器,另外5台作为测试用户终端。 每个客户端可以循环发起2000个TCP连接模拟用户服务请求。 服务器端开启8个工作线程处理IOCP的I/O完成包。

3.2测试结果

服务器端可以在1秒内完成5个客户端模拟的8000用户连接请求,并可以进行简单的数据通信。

4结束语

IOCP 篇3

随着宽带网络的普及,基于Internet的网络视频服务迅猛发展,其中颇具代表的有基于P2P技术的PPLive 、 电信运营商提供的IPTV服务等。相比传统电视,网络视频呈现出以下优势:

(1)播放电视节目更为灵活,可以提供多种频道,还可以通过点播方式选择喜爱的节目。

(2)更为丰富的节目资源、交互式和个性化的观看体验。网络视频系统可以提供丰富的节目,用户可根据分类导航和搜索功能发现特定节目,还可以根据个人喜好收藏节目,并可上传自己制作的视频内容。

网络视频在丰富人们业余生活之时,却忽略了其所造成的流量。CacheLogic公司[1]曾作过统 计,P2P应用流量占ISP下行流量 的50% ~65%、上行流量 的75% ~ 90%。目前的流量分析软件基本都是基于路由器统计分析,统计结果仅仅只针对流量类型,不能进行内容分析,而内容分析数据又分布于各网络视频提供商,需要一套系统才能对两种数据直接采集。这些数据分析可以帮助ISP服务商针对结构设计、节点选择、资源分配进行改进,对内容提供商进行网络视频系统的优化与改进提供参考依据。 基于此,本文采用IOCP技术构建 测量分析 系统,结合Android客户端数据采集,实现了一种快速的网络视频测量分析系统。

1IOCP技术介绍

IOCP是Input/Output Completion Port(I/O完成端口)的简称,是一种高性能的I/O模型,使用线程池处理异步重叠I/O(Over lapped I/O)。

IOCP[1]是一种高性能的I/O模型,其模型结构如图1所示。其应用程序使用线程池处理异步I/O请求。过去, 在处理多个并发的异步I/O请求时,有很多线程并行地运行在系统中。例如,有多个网络连接时,以往的模型会根据连接数量创建同等数量的 线程来进 行数据收 发,Windows内核需要花费大量的时间进行线程的上下文切换, 内核分配给线程的运行时间片就相对减少,而创建线程和注销线程都需要大量的时间片来完成,造成了效率低下。

IOCP采用了重叠I/O(Overlapped I/O)机制。在处理异步I/O请求时,可以创建一个工作线程来统一管理请求,在重叠请求发出后就可以做别的事情,避免了反复创建线程的开销。与此同时,IOCP充分考虑了多核处理器的硬件环境,可以根据CPU的数量来灵活地决定线程的个数,从而减少了线程的调度次数,大幅提高了性能。

2测量方法

网络视频系统测量 方法分为 主动测量 和被动测 量。 主动测量是使用爬虫进行全网搜索得到用户数据。从理论上来说这种方法不需要用户安装客户端,整个统计过程由服务端自主完成;被动测量方式是根据隐私保护协议为用户安装相应的客户端,由客户端采集用户数据后上传至服务端。被动测量有两种方式[2]:1设置观测点,用以记录和分析网络视频软件数据;2建立日志服务器,用以搜集用户行为记录等相关信息。

2.1观测点测量法

观测点测量法是根据网络的异构性设置多个不同的观测点,配置特定规则的监测工具,用于记录观看节目时产生的流媒体流量数据,通过对流量数据的分析,评估系统性能、分析服务器及网络负载特征以及数据位置信息和稳定性,进而选择系统的节点算法。此种方法基于报文长度的启发式规则:1在一个TCP会话里,累计大于1 200个字节的长报文数目超过10个(对长报文的认定可以调整),即可认定此会话为网络视频会话;2针对确定的网络视频会话,进一步筛选掉控制报文,即剩余视频报文。实践证明,该规则可以有效分离视频与控制流量。

2.2日志测量法

日志测量法是在系统中设置日志服务器,用于采集用户观看行为,根据实际需要记录用户观看的视频标题、观看时间、观看位置等信息。通过对这些记录的分析,可以基本准确地掌握用户到达模式、系统逗留时间等行为。同时可以使用流畅度模型,测量用户实际观看一个节目的时间在节目总时间里的占比。

与主动测量方法不同,被动测量较少对系统造成不良影响,而且被动测量模型可以用于多种系统,通用性较高。 基于观测点的被动测量方法受到观察角度的制约,测量结果具有片面性,但是基于系统日志的被动测量方法对测量系统有整体全面的认识。观测点测量法消耗资源较多,为了不影响用户,本文采用日志测量方法。

3系统总体架构

系统采用C/S模式,服务端为 操作系统Windows2012,采用IOCP技术搭建服务程序,客户端主要针对Android电视和手机,采用QT框架搭建客户端 程序。 客户端主要采集如下信息:用户ID、网络视频软件名称、 观看视频名称、开始时间、结束时间、流量消耗情况。系统总体架构如图2所示

IOCP服务端流程如 图3所示:1服务端首 先建立Socket连接;2建立IOCP对象并建立工作 池线程;3启动监听线程并等待用户连接;4当客户端连接后,将连接Socket和完成端 口关联,工作线程 将自动接 收该Socket号的数据包;5将接收到的数据进行处理。

Android客户端流程如图4所示:1当用户首次启动网络视频软件,如PPLive等,客户端将启动监测;2启动监测后将自动根据用户情况生成客户日志信息;3当用户结束视频观看时,客户端将连接服务端,传回日志信息。 此种处理可以避免客户端长时间占用网络连接造成的网络资源浪费。同时由于日志信息容量较大,故将日志信息保存在SQLite数据库,当网络连接成功后,再逐条将日志信息传送。即使发生用户关机等异常情况,同样可以在下次进行传送;4传送完成后,客户端将处于休眠状态,等待下一次记录开始。

4系统测试

将IOCP网络视频测量服务程序与传统的基于线程池测量服务程序进行性能对比实验,实验环境为2.6G8核8G服务器,测试结果如表1所示。

在连接数为10、100、1 000三种情况下,对CPU使用率和内存使用量两大主要指标进行对比,可以发现传统线程池模型服务器当连接数成数量级增长时,性能大幅度下降,而IOCP模式的情况要远远优于传统线程池方式。

摘要:为满足网络视频流量监控及数据统计分析需要,基于C/S模式,采用IOCP技术,设计并实现了网络视频测量分析系统。系统实现了用户网络视频相关数据的测量与统计,可为网络运行商及内容提供商的优化与改进提供参考依据。

IOCP 篇4

当前,移动互联网已成为了人们主要的获取信息的主要渠道。在移动互联网上主要有两种方式获取信息。 一是通过各种浏览器来浏览网站内容。二是通过手机上安装的app来获得来自服务器上的数据,如QQ和微信。这两种通讯方式都需要服务器端程序的支持。而衡量服务器端程序性能的一个重要指标就是并发量,也就是同时可以接入客户端的数量,本文讨论如何在windows系统下最性能的服务器端程序模型完成端口模型。

2 具体内容

首先,我们讲到同步和异步两个概念。

同步模式是比较早期的模式,在Windows套接字创建时,默认工作在同步模式下。同步模式就是需要服务器完成收发后才可以做下一步的操作,这样会大大降低程序的运行性能。所以高性能的服务器端程序多数使用异步模式。异步模式是指服务器程序不等当前I/O是否完成,就马上执行下一个任务,并不等待程序执行结果或程序本身出现错误退出。这样就大大提高了程序性能。举个例子来说,一个公司的物流公司的经理给一个快递员下达快递任务后,等待这个快递员送完快递后再给第二个快递员下达新任务。如果需要用1 分钟的时间把下单的内容通知给快递员,且第一个快递员用时完成任务1小时,第二个快递员也用时1小时完成任务,则一共用时2小时2分钟,这样的模式就是同步模式。如果经理给第一个快递员下完任务后不等待快递员执行任务的完成就直接给下一个快递员下达第二个任务,这时用时就只有2 分钟,仅仅是下单内容通知给快递员的时间,这样的模式就是异步模式。很明显,采用异步模式的程序大大提高了性能。

第二,我们讲到阻塞和非阻塞两个概念

阻塞模式就是指本线程结果返回之前,线程会被挂起该线程进入非可执行状态,CPU不给线程分配时间片,即线程暂停运行,进入待机状态。函数只会有执行结果或者出错码生成以后才会做下一步的操作。而非阻塞模式指的是不等待执行结果或出错码的出现不会直接进入睡眠状态而是马上执行下一步的操作,此时线程本身还是处在激活状态。同样用上面经理-快递员的例子来说明,阻塞模式是指经理在下达指令后一直等待快递员返回执行情况。在此期间不做任何事情,直到快递员返回唤醒经理,再进行下一个命令。而非阻塞模式指的是经理下达指令后在等待返回执行情况期间可以做其他事情,比例不停打电话给快递员询问执行情况等。

第三,我们来讲到IOCP的工作原理和编写过程。

IOCP是Windows下高性能的可伸展的I/O模型,是最高性能的模型,与其性能相当的模型都没有。IOCP全称Input/Output Completion Port,译为I/O完成端口。首先我们来说为什么Windows下要使用该模型。我们知道在网络上客户端与服务器发送和接收数据(即网络I/O操作)相对于CPU而言要花费大的时间,两者的差距可能有数几千倍之多。显然如果要CPU和网络I/O操作采用同步模式的话即让CPU等待网络I/O完成收发数据之后再做下一步的操作,对于整个系统来说是一种巨大的浪费。所以为了提高效率,让系统不等待结果而是直接做下一条操作,只是让I/O操作完成之后再通过回调函数来通知系统收发执行情况。这也是为什么叫做完成端口的原因。IOCP其实上是一个线程池。这个线程池的核心工作是去调用I/O操作完成时的回调函数。IOCP可以想象为一个包含网络通信操作即接收新客户端的加入,发送数据到客户端,接收客户端上交的数据的一个信息队列,它会把上述网络操作即接收客户端接入请求,发送数据和接收数据操作执行的结果存放在这个队列里。我们可以读出所有的网络操作的结果以及出错码。

具体实现过程:

第一步:创建一个完成端口。使用HANDLE完成端口=Create Io Completion Port(参数1,参数2,参数3,参数4);参数4 代表的是程序可以同时生成线程的最大数量。人们很自然地想到在一个CPU上运行的线程数量是越多越好。但是如果线程太多的话,系统要在不同的线程上不断地切换上下文,这样不但不能加大CPU的能力,反而会降低CPU的实际使用效率。所以我在这里只是设置为零,也就是说我们只需要让一个CPU上运行一个线程就好。

第二步:创建n个I/O操作线程。业内一般控制n的数量为CPU数量的2 倍加2,如果是4 核CPU,就是4*2+2 个即创建10个I/O操作线程。因为在网络上接收客户端数据和发送数据到客户端都是比较需要时间的事情,而在CPU上的线程操作是比较高速的,两者的差距可能是网络I/O操作用时几千ms而CPU一个线程只是用几个ms而已,所以只需要几个I/O操作线程就可以满足一台服务器上几万个客户端的accept,send,rec执行操作。

I/O操作线程用来处理上述讲到的接收客户端接入请求,发送数据和接收数据操作,也是处理我们I/O网络事件的线程。那么我们就要首先获取系统中CPU的数量以便确定I/O操作线程的具体数量。

使用SYSTEM_INFO, Get System Info来取得Windows系统信息,在Get System Info中的就有CPU的核心数量,然后如上所述生成的I/O操作线程为CPU核心数量的两倍加二。

然后:把用于监听的本地套接字绑定到完成端口上面并在程序设置的网络端口上开始监听。绑定方法为使用Create IoCompletion Port()函数。注意这里和创建完成端口的Windows API完全相同。

第三步:I/O操作线程不停地取出已有的发送数据和接收数据的结果,这些结果都存放在完成端口上,取出这些结果的函数是阻塞函数,也就是说不会被打断,除非出错。

第四步:程序的主线程里只做等待客户端的套接字连接的工作。这里可以使用Accpet()和Accept Ex()两个函数,Accept Ex是微软专门在Windows操作系统里面提供的扩展函数,使用重叠I/O机制。在Windows里的异步I/O操作都要使用重叠I/O机制。重叠I/O机制可以简单地理解为含有这种机制的操作方法和系统里别的操作是异步的,不需要和别的操作有任何联系。

扩展函数Accept Ex()的定义

BOOL Accept Ex(

生成套接字参数1, //生成用于本地监听的套接字

生成套接字参数2, //用于接受连接的socket,事先建好的,有客户端连接进来时直接把这个Socket拿给它用的那个,是Accept Ex高性能的关键所在。一般来说,根据业务的多少来确定事先准备socket的数理。

PVOID参数3, //这个为缓冲区,包含了三个信息:一是客户端发来的第一组数据,二是服务器的地址,三是客户端的地址。

DWORD参数4, //参数3中用于存放数据的空间大小。如果为零,则Accept时将不会等待数据到来,而直接返回,如果此参数不为0,那么一定得等接收到数据了才会返回。

DWORD参数5, //服务器地址信息空间的大小。

DWORD参数6,//接入客户端地址的信息空间大小。

LPDWORD参数7,//可不管理

LPOVERLAPPED参数8 //重叠I/O操作所要用到的重叠结构);

第五步:这时主线程和I/O操作线程开始分工工作,主线程处理新接入的客户端工作,就是接入连接和安排到完成端口中去。使用accept()和accept Ex()函数接入新的客户端,使用Create Io Completion Port()安排到已有的完成端口中去,同时可以在对新接入的客户端进行读写操作。

主线程一直在等待新的客户端的接入,这里采用的是阻塞模式,I/O操作线程则一直在做网络I/O操作,I/O操作线程采用的是异步非阻塞模式,只是给操作系统发命令,让操作系统去完成数据的收发工作,I/O操作线程这时并不等待系统是否完成收发工作,而是只不停的发命令,就好像上面提到的快递员-经理模式一样,这里的I/O操作线程就是经理,而做具体工作的操作系统就是快递员。经理只发命令,不监督快递员的具体工作,只是关心工作执行的结果。

在操作系统完成收发数据后,把结果发送到完成端口上来,这样完成端口上就有了所有已有客户端的收发数据执行结果。

而I/O操作线程只要读出结果就可以了,以此循环。

简单地概括完成端口模型为:

完成端口由三个主体构成,第一主线程,第二I/O操作线程,第三操作系统。首先由主线程生成一个完成端口,初始化监听套接字和生成两倍CPU数量加2 个的I/O操作线程,之后主线程的主要工作是接入新的客户端。工作线程负责命令操作系统去接收和发送数据,操作系统负责具体的收发数据工作,并把执行结果发送到完成端口上。I/O操作线程不断的读取完成端口上的收发执行结果,以确定下一步的操作,以此循环。

最后提到关闭完成端口,由于I/O操作线程是采用阻塞模式一直不停地读取操作系统放在完成端口上的执行结果,所以没有新的收发数据工作执行结果,完成端口则进入死循环中不能退出,所有我们要采用发信息的方式来使完成端口关闭。

操作系统发送完成端口退出信息的API为Post QueuedCompletion Status,实际上就是发送一个特定的网络事件给I/O操作线程,让完成端口自行退出。

代码:

摘要:本文讨论在Windows环境下,如何开发出一种基于TCP协议的高并发服务器程序。本文谈论Windows下套接字I/O模型,同步和异步I/O,阻塞和非阻塞模式,主要谈论IOCP通讯模型的原理和开发过程。

关键词:高并发,服务器端程序开发,IOCP

参考文献

[1]王艳平,张越.Windows网络与通信程序设计[M].人民邮电出版社,2013.

[2]张越.Visual C++网络程序设计实例详解[M].人民邮电出版社,2013.

[3]Jeffrey Richter.Windows核心编程Windows via C/C++[M].清华大学出版社,2011.

IOCP 篇5

1 必要性

图1是监控中心各子系统网络连接图。在Windows操作系统中通常实现网络通信程序有如下这几种模型:Select,WSAAsyncSelect,WSAEventSelect,I/O重叠模型、完成端口[1]。前面3种模型采用阻塞模式对端口进行操作,具有编程简单易用的特点,适用于数据吞吐量不大的应用。另外,在阻塞模式下,程序在处理多个客户端并发事件时需要对每一个客户开辟一个线程去处理,此时响应多个客户请求时就需要CPU不停地在每个线程之间进行上下文的切换,因为线程切换是相当浪费CPU时间的,所有阻塞通信加多线程模式是一种需要占用大量CPU时间的编程模式。

I/O重叠模型和完成端口模型都高性能的非阻塞异步通信模式[1],非阻塞的异步通信模式通常内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活地决定线程个数,而且可以减少线程调度的次数从而提高性能,大大降低了CPU的占用时间。非阻塞的异步通信模式通常编程难度大,一般只应用与大型服务器。该安防系统各子系统数据采集时间不相同,采集数据量大易导致网络上出现多个并发事件,需要数据服务器同时响应并处理并发事件,作为监控中心主机1(数据服务器)的网络通信程序必须采用高性能非阻塞的异步通信模式编写。另外,数据服务器主机同时需要负责安防态势的解算、三维场景计算及实时显示功能,对CPU和内存等系统资源使用要求较高。I/O重叠模型和完成端口模型都是高性能的非阻塞异步通信模式,考虑到编程难度相当且完成端口的性能更加优秀,因此在该项目中使用更高性能的完成端口(IOCP)模型编制服务器程序。

2 IOCP简介

完成端口(Completion Port)是一种基于重叠I/O(Overlapped I/O)的高性能异步通信机制,使用设备内核对象来协调数据的发送和接收[2]。当使用完成端口进行网络通信时,应用程序只需要向操作系统提交数据发送和接收的请求,此时应用程序可以自由地做其他事情而不会被阻塞,操作系统会在网络I/O操作“完成”之后通知应用程序,应用程序在接到系统的通知时,网络操作已经完成,此时应用程序只需要处理后面的事情了。完成端口就是不断投递重叠I/O操作,将耗时的操作交给系统后台进行,应用程序便获得了解放。

3 IOCP的实现

作为Windows操作系统最复杂的内核对象,下面简要说明完成端口实现的步骤[1]:

(1)调用CreateIoCompletionPort(HANDLE FileHandle,HANDLE ExistingCompletionPort,ULONG_PTR CompletionKey,DWORD NumberOfConcurrentThreads)函数创建一个完成端口,函数第4个参数保持为0,它指定在完成端口上每个CPU一次只允许执行一个工作者线程;

(2)判断系统内有几个CPU;

(3)创建工作者线程,根据步骤2得到的CPU信息,在完成端口上为已完成的I/O请求提供服务,为避免由于线程数量不足而使CPU处于空闲的局面,通常创建2倍于CPU数量的工作者线程以供使用;

(4)准备好一个监听套接字,绑定到本机IP上,在端口5000上监听传入的连接请求;

(5)使用AcceptEX函数,接受入站的连接请求;

(6)创建一个数据结构,用于保存单句柄数据,同时在结构中存入接受的套接字;

(7)调用CreateIoCompletionPort,将自AcceptEx返回的新套接字句柄同完成端口关联到一起,通过completionKey参数,将单句柄数据结构传递给CreateIoCom-pletionPort;

(8)开始在已接收的连接上进行I/O操作。在此,希望通过重叠I/O机制在新建的套接字上投递一个或多个异步WSARecv或WSASend请求,这些I/O请求完成后,工作者线程会为I/O请求提供服务,同时继续处理以后的I/O请求;

(9)重复步骤(5)~(8),直至服务器终止。

4 IOCP在某安防系统中的应用

数据服务器主机软件除了负责数据接收存储和转发的功能外还负责地理坐标转换、传感器数据融合、安防态势的解算、目标轨迹滤波插值、三维场景计算及实时显示功能,该软件在使用完成端口的通信模式在安防系统中的程序流程图如图2所示。

为了使用的方便以及代码的重用,在该软件中将完成端口(IOCP)封装成一个完成端口通信类CIocpServer,提供了连接、监听、发送、接收等基本网络通信功能,同时将接收到的数据保存到特定内存中,提供给上一级模块调用。

在测试该软件完成端口通信模块时,笔者采用NetAssist网络调试助手作为客户端软件,以5 ms的发送速度向该软件发送数据,为便于观察系统资源占用情况,将服务器和客户端软件放置在一台计算机上,如图3所示有数据通信时2个软件系统资源的占用情况。

图4是没有数据发送和接收时的系统资源占用情况。

图4中,紫色部分为某安防软件SZMoniSys系统占用情况,蓝色部分为网络调试助手NetAssist系统占用情况。由图可知采用完成端口作为以太网的通信程序其CUP占用率几乎可以忽略,而网络调试助手NetAssist的CUP占用率却达到了25%。如表1所示。

从表中可以看出完成端口模式在软件中使用时,繁忙和空闲时CPU占用率基本没有变化,几乎可以忽略不计,大大节约了系统硬件资源,把宝贵的系统资源留给数据分析处理、三维场景计算和显示。

另外,在今后的安防系统中,需要增减雷达、红外监视器等传感器设备时,要求监控软件具有良好的伸缩性,在该软件中由于采用了C++标准类的形式封装了完成端口,进一步提高了IOCP模型优良的扩展性能,使得该监控软件具有通用性强,扩展便捷的特点,轻松实现传感器的增减。

5 结语

本文设计了一种满足某安防系统中的高性能通信服务器端架构并完成服务器底层通信的开发。完成端口(IOCP)作为一个高效但复杂精巧的Windows内核I/O对象[3],能提供了最好的伸缩性和最高的数据吞吐率,将节约的大量宝贵系统资源留给软件需要完成的更主要功能,恰好满足服务器“高性能”的要求。在实际应用中,采用基于完成端口的通信服务模式表现出了优良的稳定性、显著的性能优势、优异的软件和硬件扩展性,同时在保证了系统高性能运行的基础上极大地降低了系统软硬件成本、系统复杂性以及维护开发成本。本文提供的基于完成端口的通信服务器在很大程度上优化了对系统资源的利用和用户的调用,经过实际应用测试,效率和性能比传统方式要高出许多,因此可以应用于水下安防系统三维视景软件数据服务器的使用。

摘要:在此给出完成端口在某水下安防系统监控软件中的一种应用,在简要介绍完成端口模型的基础上,叙述了利用完成端口实现安防系统监控软件底层通信模块的方法,并构建了一个完整的监控中心数据服务器构架。该方法提高了监控软件网络通信的数据吞吐率,节约了CUP资源,同时在该构架下能够轻松实现安防系统软硬件的扩展和升级。

关键词:完成端口(IOCP),网络通信,水下安防系统,监控软件

参考文献

[1]JONES A,OHLUND J.Microsoft Windows网络编程[M].2版.北京:清华大学出版社,2002.

[2]王新宇.IOCP模型在网络设备管理系统中的应用[C]//广西计算机学会25周年纪念会暨2011年学术年会论文集.桂林:广西计算机学会,2011.

[3][美]杰夫瑞,[法]克里斯托夫.Windows核心编程[M].5版.北京:清华大学出版社,2008.

[4]汪晓平,钟军.Visual C++网络通信协议分析与应用实现[M].北京:人民邮电出版社,2003.

[5]孙军文,安妮,王中训.基于VC++6.0的网络通信设计[J].现代电子技术,2011,34(23):52-54.

【IOCP】推荐阅读:

上一篇:对外贸易变化趋势下一篇:网上购物网站

本站热搜

    相关推荐