IOCP模型总结_第1页
IOCP模型总结_第2页
IOCP模型总结_第3页
IOCP模型总结_第4页
IOCP模型总结_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、iocp(i/o completion port,i/o 完成端口)是性能最好的一种i/o 模型。它是应用程序使用线程池处理异步i/o 请求的一种机制。在处理多个并发的异步i/o 请求时, 以往的模型都是在接收请求是创建一个线程来应答请求。这样就有很多的线程并行地运行在系统中。而这些线程都是可运行的, windows 内核花费大量的时间在进行线程的上下文切换,并没有多少时间花在线程运行上。再加上创建新线程的开销比较大,所以造成了效率的低下。调用的步骤如下:抽象出一个完成端口大概的处理流程:1:创建一个完成端口。2:创建一个线程a。3:a线程循环调用getqueuedcompletionstat

2、us()函数来得到io 操作结果,这个函数是个阻塞函数。4:主线程循环里调用accept等待客户端连接上来。5:主线程里accept返回新连接建立以后,把这个新的套接字句柄用createiocompletionport关联到完成端口,然后发出一个异步的wsasend或者 wsarecv调用,因为是异步函数,wsasend/wsarecv 会马上返回,实际的发送或者接收数据的操作由windows 系统去做。6:主线程继续下一次循环,阻塞在accept这里等待客户端连接。7:windows 系统完成 wsasend或者 wsarecv的操作,把结果发到完成端口。8:a线程里的getqueuedco

3、mpletionstatus()马上返回,并从完成端口取得刚完成的wsasend/wsarecv 的结果。9:在 a线程里对这些数据进行处理( 如果处理过程很耗时,需要新开线程处理) ,然后接着发出wsasend/wsarecv ,并继续下一次循环阻塞在getqueuedcompletionstatus()这里。归根到底概括完成端口模型一句话:我们不停地发出异步的wsasend/wsarecv io操作,具体的io 处理过程由windows 系统完成,windows 系统完成实际的io 处理后,把结果送到完成端口上(如果有多个io 都完成了,那么就在完成端口那里排成一个队列)。我们在另外一个线

4、程里从完成端口不断地取出io 操作结果,然后根据需要再发出wsasend/wsarecv io操作。而 iocp模型是事先开好了n 个线程,存储在线程池中,让他们hold 。然后将所有用户的请求都投递到一个完成端口上,然后 n个工作线程逐一地从完成端口中取得用户消息并加以处理。这样就避免了为每个用户开一个线程。既减少了线程资源,又提高了线程的利用率。完成端口模型是怎样实现的呢?我们先创建一个完成端口(:createiocompletioport())。然后再创建一个或多个工作线程,并指定他们到这个完成端口上去读取数据。我们再将远程连接的套接字句柄关联到这个完成端口(还是用:createioco

5、mpletionport())。一切就ok了。工作线程都干些什么呢?首先是调用:getqueuedcompletionstatus()函数在关联到这个完成端口上的所有套接字上等待i/o 的完成。再判断完成了什么类型的i/o 。一般来说,有三种类型的i/o ,op_accept,op_read 和 op_wirte 。我们到数据缓冲区内读取数据后,再投递一个或是多个同类型的i/o 即可( :acceptex()、:wsarecv() 、:wsasend() )。对读取到的数据,我们可以按照自己的需要来进行相应的处理。为此,我们需要一个以overlapped(重叠 i/o )结构为第一个字段的pe

6、r-i/o数据自定义结构。typedef struct _per_io_data overlapped ol; / 重叠 i/o 结构 char bufbuffer_size; / 数据缓冲区 int noperationtype; /i/o操作类型#define op_read 1 #define op_write 2 #define op_accept 3 per_io_data, *pper_io_data; 将一个 per_io_data 结构强制转化成一个overlapped 结构传给 :getqueuedcompletionstatus()函数,返回的这个per_io_data结构

7、的的 noperationtype就是 i/o 操作的类型。当然,这些类型都是在投递i/o 请求时自己设置的。这样一个iocp服务器的框架就出来了。当然,要做一个好的iocp服务器,还有考虑很多问题,如内存资源管理、接受连接的方法、恶意的客户连接、包的重排序等等。以上是个人对于iocp模型的一些理解与看法,还有待完善。另外各winsock api的用法参见 msdn 。补充 iocp模型的实现:/ 创建一个完成端口handle fcompletport = createiocompletionport( invalid_handle_value, 0,0,0 ); / 接受远程连接,并把这个连

8、接的socket句柄绑定到刚才创建的iocp上aconnect = accept( flistensock, addr, len); createiocompletionport( aconnect, fcompletport, null, 0 ); / 创建 cpu数*2 + 2个线程system_info si;getsysteminfo(&si);for (int i=1;si.dwnumberofprocessors*2+2;i+) athread = trecvsendthread.create( false ); athread.completport = fcomplet

9、port;/告诉这个线程,你要去这个iocp去访问数据 ok ,就这么简单,我们要做的就是建立一个iocp,把远程连接的socket句柄绑定到刚才创建的iocp 上,最后创建n 个线程,并告诉这n 个线程到这个iocp 上去访问数据就可以了。再看一下trecvsendthread 线程都干些什么:void trecvsendthread.execute(.) while (!self.terminated) /查询 iocp状态(数据读写操作是否完成) getqueuedcompletionstatus( completport, bytestransd, completkey, poverl

10、apped(pperiodat), time_out ); if (bytestransd !=0) . .;/数据读写操作完成 /再投递一个读数据请求 wsarecv( completkey, &(pperiodat-bufdata), 1, bytesrecv, flags, &(pperiodat-overlap), null ); 读写线程只是简单地检查iocp是否完成了我们投递的读写操作,如果完成了则再投递一个新的读写请求。应该注意到,我们创建的所有trecvsendthread 都在访问同一个iocp(因为我们只创建了一个iocp),并且我们没有使用临界区!难道不会

11、产生冲突吗?不用考虑同步问题吗?呵呵,这正是iocp 的奥妙所在。 iocp 不是一个普通的对象,不需要考虑线程安全问题。它会自动调配访问它的线程:如果某个socket上有一个线程a正在访问,那么线程b 的访问请求会被分配到另外一个socket 。这一切都是由系统自动调配的,我们无需过问。实例: /* * * copyright (c) 2008, xxxxx有限公司* all rights reserved. * * 文件名称: iocpheader.h * 摘要: iocp定义文件* * 当前版本: 1.0 * 作者:吴会然* 完成日期: 2008-9-16 * * 取代版本:* 原 作者

12、:* 完成日期:* */ #ifndef _iocpheader_h_20080916_ #define _iocpheader_h_20080916_ #include #include #define buffer_size 1024 /* * per_handle 数据*/ typedef struct _per_handle_data socket s; / 对应的套接字句柄 sockaddr_in addr; / 对方的地址per_handle_data, *pper_handle_data; /* * per_io 数据*/ typedef struct _per_io_data

13、overlapped ol; / 重叠结构 char bufbuffer_size; / 数据缓冲区 int noperationtype; / 操作类型#define op_read 1 #define op_write 2 #define op_accept 3 per_io_data, *pper_io_data; #endif /* * * copyright (c) 2008, xxxxx有限公司* all rights reserved. * * 文件名称: main.cpp * 摘要: iocp demo * * 当前版本: 1.0 * 作者:吴会然* 完成日期: 2008-9-

14、16 * * 取代版本:* 原 作者:* 完成日期:* */ #include #include #include iocpheader.h using namespace std; dword winapi serverthread( lpvoid lpparam ); int main( int argc, char *argv ) / wsadata wsadata; if( 0 != wsastartup( makeword( 2, 2 ), &wsadata ) ) printf( using %s (status:%s)n, wsadata.szdescription, w

15、sadata.szsystemstatus ); printf( with api versions: %d.%d to %d.%d, lobyte( wsadata.wversion), hibyte( wsadata.wversion ), lobyte( wsadata.whighversion), hibyte( wsadata.whighversion) ); return -1; else printf(windows sockets 2.2 startupn); / int nport = 20055; / 创建完成端口对象 / 创建工作线程处理完成端口对象的事件 handle

16、hiocp = :createiocompletionport( invalid_handle_value, 0, 0, 0 ); :createthread( null, 0, serverthread, (lpvoid)hiocp, 0, 0 ); / 创建监听套接字,绑定本地端口,开始监听 socket slisten = :socket( af_inet,-sock_stream, 0 ); sockaddr_in addr; addr.sin_family = af_inet; addr.sin_port = :htons( nport ); addr.sin_addr.s_un.s

17、_addr = inaddr_any; :bind( slisten, (sockaddr *)&addr, sizeof( addr ) ); :listen( slisten, 5 ); printf( iocp demo start.n ); / 循环处理到来的请求 while ( true ) / 等待接受未决的连接请求 sockaddr_in saremote; int nremotelen = sizeof( saremote ); socket sremote = :accept( slisten, (sockaddr *)&saremote, &nrem

18、otelen ); / 接受到新连接之后, 为它创建一个 per_handle 数据,并将他们关联到完成端口对象 pper_handle_data pperhandle = ( pper_handle_data ):globalalloc( gptr, sizeof( pper_handle_data ) ); if( pperhandle = null ) break; pperhandle-s = sremote; memcpy( &pperhandle-addr, &saremote, nremotelen ); :createiocompletionport( ( ha

19、ndle)pperhandle-s, hiocp, (dword)pperhandle, 0 ); / 投递一个接受请求 pper_io_data piodata = ( pper_io_data ):globalalloc( gptr, sizeof( pper_io_data ) ); if( piodata = null ) break; piodata-noperationtype = op_read; wsabuf buf; buf.buf = piodata-buf; buf.len = buffer_size; dword dwrecv = 0; dword dwflags =

20、0; :wsarecv( pperhandle-s, &buf, 1, &dwrecv, &dwflags, &piodata-ol, null ); / error_proc: wsacleanup(); / return 0; /* * 函数介绍:处理完成端口对象事件的线程* 输入参数:* 输出参数:* 返回值 :*/ dword winapi serverthread( lpvoid lpparam ) handle hiocp = ( handle )lpparam; if( hiocp = null ) return -1; dword dwtrans = 0; pper_handle_data pperhandle; pper_io_data pperio; while( true ) / 在关联到此完成端口的所有套接字上等待i/o 完成 bool bret = :getqueuedcompletionstatus( hiocp, &dwtrans, (lpdword)&pperhandle, (lpoverlappe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论