您的位置:首页 > 理论基础 > 计算机网络

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

2012-02-19 22:14 1326 查看
上一篇《IOCP浅析》中翻翻的谈了一下IOCP的简单含义,这篇稍微深入讨论下IOCP到底有什么好的,让大家将他推向神坛,同时简单的讨论下基本函数。

IOCP出现的意义?

写过网络程序的朋友应该很清楚网络程序的原型代码,startup一个WSADATA,然后建立一个监听socket对象,绑定一个服务器地址,然后开始监听,无限循环的accept来自客户端的消息,建立一个线程来处理消息,accept之后线程就被挂起了,知道收到来自客户端的消息。

这样的模型中服务器对每个客户端都会创建一个线程,优点在于等待请求的线程只做很少的事情,大部分时间该线程都在休息,因为recv函数是阻塞的。

所以这样的效率并不是很高,NT小组意识到这样CPU的大部分时间都耗费在线程的上下文切换上,线程并没有抢到cpu时间来处理自己的工作。

NT小组想到了一个解决办法,实现开好N个线程,将用户的消息都投递到一个消息队列中去,然后事先开好的N个线程逐一从消息队列中取出消息并加以处理,就可以避免为每一个客户端的请求单独开线程,既减少了线程的资源,也提高了线程的利用率。所以I/O完成端口的内核对象在NT3.5中首次被引入,MS还是比较伟大的。

这里你也看到了,IOCP其实称作是一种消息处理的机制差不多,而叫完成端口估计也是有历史原因,亦或者是因为他提供了用户与操作系统的一种接口吧。

ICOP的基本函数接口
创建完成端口

C++

HANDLE WINAPI CreateIoCompletionPort(
__in HANDLE FileHandle, // An open file handle or INVALID_HANDLE_VALUE
__in_opt HANDLE 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
);
1
2
3
4
5
6
HANDLE WINAPI CreateIoCompletionPort(

    __in      HANDLE FileHandle,                // An open file handle or INVALID_HANDLE_VALUE

    __in_opt  HANDLE 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的异步调用

C++

BOOL WINAPI PostQueuedCompletionStatus(
__in HANDLE CompletionPort,
__in DWORD dwNumberOfBytesTransferred,
__in ULONG_PTR dwCompletionKey,
__in_opt LPOVERLAPPED lpOverlapped
);
1
2
3
4
5
6
BOOL WINAPI PostQueuedCompletionStatus(

  __in      HANDLE CompletionPort,

  __in      DWORD dwNumberOfBytesTransferred,

  __in      ULONG_PTR dwCompletionKey,

  __in_opt  LPOVERLAPPED lpOverlapped

);

第一个参数为创建的完成端口句柄
第二个参数传输了多少字节
第三个参数同样为完成键指针
第四个参数为重叠I/O buffer,其结构如下

C

typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _OVERLAPPED {

    ULONG_PTR Internal;

    ULONG_PTR InternalHigh;

    union {

        struct {

            DWORD Offset;

            DWORD OffsetHigh;

        };

        PVOID  Pointer;

    };

    HANDLE    hEvent;

} OVERLAPPED, *LPOVERLAPPED;

线程的同步

C++

BOOL WINAPI GetQueuedCompletionStatus(
__in HANDLE CompletionPort,
__out LPDWORD lpNumberOfBytes,
__out PULONG_PTR lpCompletionKey,
__out LPOVERLAPPED *lpOverlapped,
__in DWORD dwMilliseconds
);
1
2
3
4
5
6
7
BOOL WINAPI GetQueuedCompletionStatus(

  __in   HANDLE CompletionPort,

  __out  LPDWORD lpNumberOfBytes,

  __out  PULONG_PTR lpCompletionKey,

  __out  LPOVERLAPPED *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就介绍到这里,下一篇会尝试着写出一个简单的完成端口模型来通讯,这篇可能会比较晚出来,因为自己也是摸索阶段,大家互勉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  API IOCP 网络编程