winston 发表于 2012-2-29 15:03:56

IOCP浅析[二]——IOCP出现的意义和函数接口

上一篇《IOCP浅析》中翻翻的谈了一下IOCP的简单含义,这篇稍微深入讨论下IOCP到底有什么好的,让大家将他推向神坛,同时简单的讨论下基本函数。
IOCP出现的意义?
写过网络程序的朋友应该很清楚网络程序的原型代码,startup一个WSADATA,然后建立一个监听socket对象,绑定一个服务器地址,然后开始监听,无限循环的accept来自客户端的消息,建立一个线程来处理消息,accept之后线程就被挂起了,知道收到来自客户端的消息。
这样的模型中服务器对每个客户端都会创建一个线程,优点在于等待请求的线程只做很少的事情,大部分时间该线程都在休息,因为recv函数是阻塞的。
所以这样的效率并不是很高,NT小组意识到这样CPU的大部分时间都耗费在线程的上下文切换上,线程并没有抢到cpu时间来处理自己的工作。
NT小组想到了一个解决办法,实现开好N个线程,将用户的消息都投递到一个消息队列中去,然后事先开好的N个线程逐一从消息队列中取出消息并加以处理,就可以避免为每一个客户端的请求单独开线程,既减少了线程的资源,也提高了线程的利用率。所以I/O完成端口的内核对象在NT3.5中首次被引入,MS还是比较伟大的。
这里你也看到了,IOCP其实称作是一种消息处理的机制差不多,而叫完成端口估计也是有历史原因,亦或者是因为他提供了用户与操作系统的一种接口吧。
ICOP的基本函数接口
创建完成端口
HANDLE WINAPI CreateIoCompletionPort(
        __in      HANDLE FileHandle,                                // An open file handle or INVALID_HANDLE_VALUE
        __in_optHANDLE ExistingCompletionPort,        // A handle to an existing I/O completion port or NULL
        __in      ULONG_PTR CompletionKey,                        // Completion key
        __in      DWORD NumberOfConcurrentThreads        // Number of threads to execute concurrently
        );


第一个参数是指一个已经打开的文件句柄或者空句柄值,一般为客户端的socket 注意:第一个参数HANDLE在创建时需要在CreateFile()中制定FILE_FLAG_OVERLAPPED标志。第二个参数是指一个已经存在的IOCP句柄或者NULL
第三个参数是指完成Key,是一个unsigned long的指针,可以为NULL
第四个参数才是我们比较关心的,是指已经创建好的线程数,一般我们会用一个公式来计算,预设的线程数 = CPU核心数 * 2 + 2,有人也说是 + 1,我是没明白为什么要这样计算,希望大神指教。
对于第三个参数的意思,MSDN上解释如下 Use the CompletionKey parameter to help your application track which I/O operations have completed.(用来检测那些IO操作已经完成)
该函数用于两个不同的目的
1.创建一个完成端口的句柄对象
HANDLE h = CreateIoCompletionPort((HANDLE) socket, hCompletionPort, dwCompletionKey, m_nIOWorkers);
2.将一个句柄和完成端口关联在一起
在绑定每一个CLIENT到IOCP时,需要传递一个DWORD CompletionKey, 该参数为CLIENT信息的一个指针。
IO的异步调用
BOOL WINAPI PostQueuedCompletionStatus(
__in      HANDLE CompletionPort,
__in      DWORD dwNumberOfBytesTransferred,
__in      ULONG_PTR dwCompletionKey,
__in_optLPOVERLAPPED lpOverlapped
);
第一个参数为创建的完成端口句柄
第二个参数传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer,其结构如下
typedef struct _OVERLAPPED {
        ULONG_PTR Internal;
        ULONG_PTR InternalHigh;
        union {
                struct {
                        DWORD Offset;
                        DWORD OffsetHigh;
                };
                PVOIDPointer;
        };
        HANDLE    hEvent;
} OVERLAPPED, *LPOVERLAPPED;
线程的同步
BOOL WINAPI GetQueuedCompletionStatus(
__in   HANDLE CompletionPort,
__outLPDWORD lpNumberOfBytes,
__outPULONG_PTR lpCompletionKey,
__outLPOVERLAPPED *lpOverlapped,
__in   DWORD dwMilliseconds
);
第一个参数为创建的完成端口句柄
第二个参数同样为传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer
第五个参数的解释如下
The number of milliseconds that the caller is willing to wait for a completion packet to appear at the completion port. If a completion packet does not appear within the specified time, the function times out, returns FALSE, and sets *lpOverlapped to NULL.(等待完成端口上的完成packet出现的毫秒数。如果一个完成在特殊时间内没有出现,则认为超时,返回false,同时将重叠buffer置为NULL)
大体上函数就有这么几个,大家有兴趣可以去看看MSDN上关于完成端口上的英文介绍,比较准确,中文翻译上难免出现歧义,同时还可以锻炼英文阅读。
好了,I/O完成端口的API就介绍到这里,下一篇会尝试着写出一个简单的完成端口模型来通讯,这篇可能会比较晚出来,因为自己也是摸索阶段,大家互勉。

页: [1]
查看完整版本: IOCP浅析[二]——IOCP出现的意义和函数接口