IOCP,先从概念上认识一下。IOCP全称I/O Completion Port,中文译为I/O完成端口。是Windows平台最高效的I/O模块,现在IIS服务器,就采用IOCP模型。IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。与使用select()或是其它异步方法不同的是,现在很多书,文字都直接将IOCP模块和网络编程关联起来,好像IOCP就是和网络打交道的。典型的IOCP模型的使用,是 将一个套接字(socket)与一个完成端口关联了起来,当一个网络事件发生的时候,Windows将此完成端口加入一个队列中,然后应用程序可以对核心层进行查询以得到此完成端口。本文的重点,不是将网络编程,而是把IOCP当作队列来用。经测试,ICOP模型队列,是如此的高效,让人惊叹!
先认识一下IOCP模型三个重要的API函数。IOCP模型队列,是先进先出。先投递,先被通知,适合多线程下工作。
DelphiXE,Windows下三个函数原型。
//创建IOCP完成端口句柄
function CreateIoCompletionPort(FileHandle, ExistingCompletionPort: THandle;
CompletionKey, NumberOfConcurrentThreads: DWORD): THandle; stdcall;
//获取IOCP事件
function GetQueuedCompletionStatus(CompletionPort: THandle;
var lpNumberOfBytesTransferred, lpCompletionKey: DWORD;
var lpOverlapped: POverlapped; dwMilliseconds: DWORD): BOOL; stdcall;
//投递IOCP事件
function PostQueuedCompletionStatus(CompletionPort: THandle; dwNumberOfBytesTransferred: DWORD;
dwCompletionKey: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
{$EXTERNALSYM PostQueuedCompletionStatus}
下面是实现代码:
unit IOCPQueue;
interface
uses windows, classes;
type
TOnQueueProc = procedure(sender: tobject; ParamA, ParamB: integer) of object;
TIOCPQueue = class
private
FCompletionPort: THandle;
FOnQueueProc: TOnQueueProc;
FOverlapped: Overlapped;
procedure Run;
public
constructor create(OnQueueProc: TOnQueueProc);
destructor Destroy; override;
procedure PostQueueState(ParamA, ParamB: integer);
procedure Close;
end;
implementation
uses SysUtils;
{ TIOCPQueuue }
//Post关闭消息
procedure TIOCPQueue.Close;
begin
PostQueuedCompletionStatus(FCompletionPort, 0, 0, @FOverlapped);
end;
//创建完成端口
constructor TIOCPQueue.create;
begin
FOnQueueProc := OnQueueProc;
FCompletionPort := CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
if FCompletionPort = 0 then
raise Exception.Create(‘TIOCPQueue Create Error FCompletionPort=0‘);
TThread.CreateAnonymousThread(Run).Start;
end;
//关闭完成端口句柄
destructor TIOCPQueue.Destroy;
begin
Close;
CloseHandle(FCompletionPort);
inherited;
end;
//提交完成端口消息
procedure TIOCPQueue.PostQueueState(ParamA, ParamB: integer);
begin
PostQueuedCompletionStatus(FCompletionPort, ParamA, ParamB, nil);
end;
//查询完成端口,状态
procedure TIOCPQueue.Run;
var
Transfered: DWORD;
{$IF RTLVersion > 22.0} //XE2,XE3
key: NativeUInt ;
{$ELSE}
key: DWORD;
{$IFEND}
o: POverlapped;
ret: bool;
begin
while true do
begin
ret := GetQueuedCompletionStatus(FCompletionPort, Transfered,
key, POverlapped(o), INFINITE);
if ret then
begin
if o = nil then
FOnQueueProc(self, Transfered, key)
else
break;
end;
end;
end;
end.