IOCP 系列函数讲解

来源:互联网 发布:mac安装win10启动黑屏 编辑:程序博客网 时间:2024/06/05 05:00

  • CreateIoCompletionPort详解
  • GetQueuedCompletionStatus
  • PostQueuedCompletionStatus
  • WSASocket
    • Socket与WSASocket的区别
  • WSAEventSelect
  • WSARecv

CreateIoCompletionPort()详解

函数原型:

HANDLE WINAPI CreateIoCompletionPort(  __in          HANDLE FileHandle,  __in          HANDLE ExistingCompletionPort,  __in          ULONG_PTR CompletionKey,  __in          DWORD NumberOfConcurrentThreads);

  一个I/O完成端口关联一个或多个文件句柄,也可以在创建I/O完成端口的时候 没有关联任何文件句柄。一个I/O完成端口关联一个打开文件的实例使应用程序可以收到包括这个文件异步I/O操作的完成通知。

参数:
FileHandle 打开重叠IO完成端口的文件句柄
如果设置这个参数为INVALID_HANDLE_VALUE,那 么,CreateIoCompletionPort 会创建一个不关联任何文件的完成端口,而且ExistingCompletionPort 必须设置为NULL,CompletionKey 也将被忽略。

ExistingCompletionPort 完成端口句柄
如果指定一个已经存在的完成端口,函数将关联 FileHandle 指定的文件,并返回已存在的完成端口句柄,函数不会创建一个新的完成端口。
如果这个参数为NULL,函数创建一个与FileHandle指定的文 件关联的完成端口,并返回一个新的完成端口句柄。

CompletionKey 单文件句柄,包含指定文件每次IO完成包数据信息。

NumberOfConcurrentThreads 系统允许在完成端口上并发处理IO完成包的最大线程数量。如果 ExistingCompletionPort 为NULL,此参数忽略

返回值:
如果执行成功,函数返回关联指定文件的完成端口句柄;否则,返回NULL

备注:
  CreateIoCompletionPort 提供这个功能:I/O系统可以被用来向列队的I/O完成端口发送I/O完成通知包。当 你执行一个已经关联一个完成端口的文件I/O操作,I/O系统将会在这个I/O操作完成的时候向I/O完成端口发送一个完成通知包,I/O完成端口将以先 进先出的方式放置这个I/O完成通知包,并使用GetQueuedCompletionStatus 接收I/O完成通知包。
  虽然允许任何数量的 线程来调用 GetQueuedCompletionStatus 等待一个I/O完成端口,但每个线程只能同时间内关联一个I/O完成端口,且此端口是线程最后检查的那个端口。
  当一个包被放入队列中,系统首先会 检查有多少个关联此端口的线程在运行,如果运行的线程的数量少于NumberOfConcurrentThreads的值,那么允许其中的一个等 待线程去处理包。当一个运行的线程完成处理,将再次调用GetQueuedCompletionStatus ,此时系统允许另一个等待线程去处理包。
  系 统也允许一个等待的线程处理包如果运行的线程进入任何形式的等待状态,当这个线程从等待状态进入运行状态,可能会有一个很短的时期活动线程的数量会超过 NumberOfConcurrentThreads 的值,此时,系统会通过不允许任何新的活动线程快速的减少线程个数,直到活动线程少于NumberOfConcurrentThreads 的值。
参考链接:
CreateIoCompletionPort和完成端口

GetQueuedCompletionStatus

  完成端口GetQueuedCompletionStatus返回值的问题

  先看看GetQueuedCompletionStatus函数的完整声明:

BOOL GetQueuedCompletionStatus(    HANDLE CompletionPort,           LPDWORD lpNumberOfBytes,        PULONG_PTR lpCompletionKey,     LPOVERLAPPED *lpOverlapped,     DWORD dwMilliseconds);

  再看看MSDN上对其返回值的说明:

  If the function dequeues a completion packet for a successful I/O operation from the completion port, the return value is nonzero. The function stores information in the variables pointed to by the lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped parameters.
  如果函数从完成端口取出一个成功I/O操作的完成包,返回值为非0。函数在lpNumberOfBytes, lpCompletionKey, and lpOverlapped指向的参数中存储相关信息。

  If *lpOverlapped is NULL and the function does not dequeue a completion packet from the completion port, the return value is zero. The function does not store information in the variables pointed to by the lpNumberOfBytesTransferred and lpCompletionKey parameters. To get extended error information, call GetLastError. If the function did not dequeue a completion packet because the wait timed out, GetLastError returns WAIT_TIMEOUT.
  如果 *lpOverlapped为NULL并且函数没有从完成端口取出完成包,返回值则为0。函数则不会在lpNumberOfBytes and lpCompletionKey所指向的参数中存储信息。调用GetLastError可以得到一个扩展错误信息。如果函数由于等待超时而未能出列完成包,GetLastError返回WAIT_TIMEOUT.

  If *lpOverlapped is not NULL and the function dequeues a completion packet for a failed I/O operation from the completion port, the return value is zero. The function stores information in the variables pointed to by lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped. To get extended error information, call GetLastError
  如果 *lpOverlapped不为空并且函数从完成端口出列一个失败I/O操作的完成包,返回值为0。函数在指向lpNumberOfBytesTransferred, lpCompletionKey, and lpOverlapped的参数指针中存储相关信息。调用GetLastError可以得到扩展错误信息。

  If a socket handle associated with a completion port is closed, GetQueuedCompletionStatus returns ERROR_SUCCESS, with lpNumberOfBytes equal zero.
  如果关联到一个完成端口的一个socket句柄被关闭了,则GetQueuedCompletionStatus返回ERROR_SUCCESS,并且lpNumberOfBytes等于0

参考链接
GetQueuedCompletionStatus的返回值

PostQueuedCompletionStatus

函数原型:

BOOL WINAPI PostQueuedCompletionStatus(  _In_     HANDLE       CompletionPort,  _In_     DWORD        dwNumberOfBytesTransferred,  _In_     ULONG_PTR    dwCompletionKey,  _In_opt_ LPOVERLAPPED lpOverlapped);

CompletionPort:指定想向其发送一个完成数据包的完成端口对象。
dwNumberOfBytesTrlansferred:指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数
dwCompletlonKey:指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数
lpoverlapped:指定—个值,直接传递给GetQueuedCompletionStatus函数中对应的参数

  可以看到上面后三个参数都可以传递给GetQueuedCompletionStatus,这样—来。—个工作者线程收到传递过来的三个GetQueuedCompletionStatus函数参数后,便可根据由这三个参数的某一个设置的特殊值,决定何时应该退出。例如,可用dwCompletionPort参数传递0值,而—个工作者线程会将其解释成中止指令。一旦所有工作者线程都已关闭,便可使用CloseHandle函数,关闭完成端口。最终安全退出程序。
  PostQueuedCompletionStatus函数提供了一种方式来与线程池中的所有线程进行通信。如,当用户终止服务应用程序时,我们想要所有线程都完全利索地退出。但是如果各线程还在等待完成端口而又没有已完成的I/O 请求,那么它们将无法被唤醒。
  通过为线程池中的每个线程都调用一次PostQueuedCompletionStatus,我们可以将它们都唤醒。每个线程会对GetQueuedCompletionStatus的返回值进行检查,如果发现应用程序正在终止,那么它们就可以进行清理工作并正常地退出。
  这个函数成功返回0,失败返回非0,但是如果当此函数返回 false,并且当 GetLastError() == ERROR_IO_PENDING 的时候,认为它是成功的。

参考
MSDN
Can PostQueuedCompletionStatus ever fail?

WSASocket

  函数原型

SOCKET WSASocket(  _In_ int                af,  _In_ int                type,  _In_ int                protocol,  _In_ LPWSAPROTOCOL_INFO lpProtocolInfo,  _In_ GROUP              g,  _In_ DWORD              dwFlags);

  参数说明:
af:[in]: 一个地址族规范。目前仅支持AF_INET格式,亦即ARPA Internet地址格式。
type:新套接口的类型描述。
protocol:套接口使用的特定协议,如果调用者不愿指定协议则定为0。
lpProtocolInfo:一个指向PROTOCOL_INFO结构的指针,该结构定义所创建套接口的特性。如果本参数非零,则前三个参数(af, type, protocol)被忽略。
g:保留给未来使用的套接字组。套接口组的标识符。
iFlags:套接口属性描述。

Socket与WSASocket的区别

  socket和UNIX兼容,等价于用默认选项调用WSASocket。
  WSASocket可以使用WinSock特有功能,比如重叠IO,用dwflags指定。

  wsa的a是指api,用于区别spi,因为在spi中还有wspsocket,wspaccept等…再说一下winsock分两部分:winsock api,winsock spi。。。

  WSASocket()在Socket()上扩展了一些功能,可以让你详细的来“定制”,一个socket如果只是简单的使用就没有必要使用WSASocket()

WSASocket用于非阻塞,很好用,Socket用于阻塞,也可采用多线程实现非阻塞

函数返回的错误代码:

WSANOTINITIALISED                在调用本API之前应成功调用WSAStartup()。WSAENETDOWN                 网络子系统失效。WSAEAFNOSUPPORT                不支持指定的地址族。WSAEINPROGRESS                一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数WSAEMFILE                                无可用的套接口描述字。WSAENOBUFS                        无可用的缓冲区空间。套接口无法创建。WSAEPROTONOSUPPORT        不支持指定的协议。WSAEPROTOTYPE                指定的协议对于本套接口类型错误。WSAESOCKTNOSUPPORT        本地址族不支持指定的套接口类型。WSAEINVAL                                g参数非法。

其实这个函数每个参数都有很复杂的讲解。
具体可以参见MSDN文档。

WSAEventSelect

  WSAEventSelect模型是WindowsSockets提供的一个有用异步I/O模型。该模型允许在一个或者多个套接字上接收以事件为基础的网络事件通知。Windows Sockets应用程序在创建套接字后,调用WSAEventSelect()函数,将一个事件对象与网络事件集合关联在一起。当网络事件发生时,应用程序以事件的形式接收网络事件通知。
  使用这个模型的基本思路是为感兴趣的一组网络事件创建一个事件对象,再调用WSAEventSelect()函数将网络事件和事件对象关联起来。当网络事件发生时,Winsock使相应的事件对象受信,在事件对象上的等待函数就会返回。
  Winsock中创建事件对象的函数是WSACreateEvent,定义如下:

WSAEVENT WSACreateEvent(void); //返回一个手工重置的事件对象句柄

  创建事件对象之后,必须调用WSAEventSelect函数将指定的一组网络事件与它关联在一起。

  WSAEventSelect模型简单易用,也不需要窗口环境。该模型唯一的缺点是有最多等待64个事件对象的限制,当套接字连接数量增加时,就必须创建多个线程来处理I/O,也就是所谓的线程池。
  与WSAAsyncSelect一样也是一种异步事件通知模型,不同的是WSAAsyncSelect是与窗口句柄关联在一起的,必须要要窗口才行,而WSAEventSelect是与事件对象关联的。这个模型的基本思路是为感兴趣的一组网络事件创建一个事件对象,再调用WSAEventSelect函数将网络事件和事件对象关联起来。当网络事件发生时,winsock使响应的事件对象受信,在事件对象上等待的函数就会立即返回。之后调用WSAEnumNetworkEvents函数便可获得到底发生了什么网络事件(FD_READ/FD_ACCEPT/FD_CLOSE等等)。

WSARecv

函数原型:

int WSARecv(  _In_    SOCKET                             s,  _Inout_ LPWSABUF                           lpBuffers,  _In_    DWORD                              dwBufferCount,  _Out_   LPDWORD                            lpNumberOfBytesRecvd,  _Inout_ LPDWORD                            lpFlags,  _In_    LPWSAOVERLAPPED                    lpOverlapped,  _In_    LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

  将一个套结字邦定到完成端口后,调用WSARecv和WSASend会立即返回,提高了系统的效率。可以以完成端口为参数调用 GetQueuedCompletionStatus 通过返回参数 lpOverlapped结构来区分来WSARecv和WSASend 。这样主程序就可以完全等待接受新的连接,线程程序来等待WSARecv和WSASend是否完成了。

0 0
原创粉丝点击