目录
1、重叠I/O
(1)概念
(2)重叠数据结构WSAOVERLAPPED
2、重叠I/O的相关函数
(1)套接字创建
(2)发送数据函数
(3)两种获取传输数据数量的方法
3、 重叠I/O模型的编程框架
(1)使用事件通知方式进行重叠I/O的编程框架
(2)使用完成例程方式进行重叠I/O的编程框架
(3)以面向连接额的数据接收为例
4、重叠I/O模型评价
1、重叠I/O
(1)概念
- 重叠I/O模型是以Windows重叠I/O机制为基础的套接字I/O模型。Windows重叠I/O本来是一种文件操作技术。在传统文件操作中,文件的读写函数都是以阻塞模式工作的,当文件很大或磁盘读写速度较低时,程序运行就会长时间阻塞在文件的读写操作上,直到读写完成才返回。这样将浪费很多时间,导致程序性能下降。为了解决这个问题,Windows引进了重叠I/O的概念。能同时以多个线程处理多个I/O。
- 在重叠I/O下,应用程序在调用文件读写函数后函数会立即返回,而不必等待操作结束,文件读写的同时应用程序可以执行其他操作,这就是所谓的异步I/O操作。如果让应用程序连续进行多个文件读写函数的调用,使得系统同时执行多个文件的读写操作,就成为所谓的重叠I/O操作
- WinSock的重叠I/O模型就是以重叠I/O机制为基础开发的。从WinSock2开始,重叠I/O模型便被引入到WinSock的扩展套接字函数中,这些扩展函数的格式不再与BSD套接字函数兼容,函数名均以WSA开头,比如recv()函数和send()函数的Windows扩展版分别为WSARecv()和WSASend()。应用程序要使用重叠I/O模型,就必须使用WinSock扩展套接字函数。
(2)重叠数据结构WSAOVERLAPPED
typedef struct _WSAOVERLAPPED{
ULONG_PTR Interal; //底层操作系统使用
ULONG_PTR InteralHigh; //底层操作系统使用
union{
struct{
DWORD offset; //套接字是忽略,文件操作使用。
DWORD offsetHigh; //忽略
};
PVOID Pointer; //忽略
};
HANDLE hEvent;//允许应用程序为这个操作关联一个事件对象句柄
}WSAOVERLAPPED, *LPWSAOVERLAPPED;
- 重叠I/O的事件通知方法需要Windows事件对象关联到WSAOVERLAPPED结构。当I/O完成时,会将WSAOVERLAPPED结构中的hEvents置为有信号状态。
- 通过调用WSAWaitForMultipleEvents()来等待I/O完成的通知,在得到通知信号后,就可以调用WSAGetOverlappedResult()来查询I/O操作的结果,并进行相关处理。WSAOVERLAPPED结构在重叠I/O请求初始化及其后续的完成之间提供一个沟通或通信机制。
2、重叠I/O的相关函数
(1)套接字创建
SOCKET WSASocket{
int af, int type, int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,//指定新套接字的特性
GROUP g, //保留
DWORD dwFlags//在重叠I/O模型中,需要设置为WSA_FLAG_OVERLAPPED。
};
(2)发送数据函数
int WSASend{
SOCKET s,
LPWSABUF lpBuffers,//指向WSABUF结构数组的指针
DWORD dwBufferCount,//记录lpBuffers数组中WSABUF结构的数目
LPDWORD lpNumberOfBytesSent, //返回指向发送的字节数的指针
DWORD dwFlags, //标志
LPWSAOVERLAPPED lpOverlapped, //指向重叠结构的指针
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
//指向发送操作完成后调用的完成例程
};
如果重叠操作立即完成,则返回0;如果重叠操作被成功初始化,并且稍后完成,则返回WSA_IO_PENDING。
(3)两种获取传输数据数量的方法
- 1)如果指定了完成例程,通过cbTransferred参数获取
- 2)通过WSAGetOverlappedResult()的参数lpcbTransferred获取。
3、 重叠I/O模型的编程框架
WinSock可以使用事件通知和完成例程两种方式来实现重叠I/O的操作。
(1)使用事件通知方式进行重叠I/O的编程框架
- 套接字初始化,设置为重叠I/O模式;
- 创建套接字网络事件对应的用户事件对象;
- 初始化重叠结构,为套接字管理事件对象;
- 异步接收数据,无论能否接收到数据,都会直接返回;
- 调用WSAWaitForMultipleEvents(),在所有事件对象上等待,只要有一个事件对象变为授信状态,则返回;
- 调用WSAGetOverlappedResult(),获取套接字上的重叠操作状态,并保存到重叠结构中;
- 根据重置事件的状态进行处理;
- 重置已授信的事件对象、重叠结构、标志位和缓冲区;
- 回到步骤4。
(2)使用完成例程方式进行重叠I/O的编程框架
对于网络重叠I/O操作,等待I/O操作结束的另一种方法是使用完成例程。异步的发送和接收接口函数的参数中的最后一个参数lpCompletionROUTINE就是用来指向完成例程的指针。若指定此参数,hEvent参数将被忽略,上下文信息将传送给完成例程函数。
①完成例程函数原型
void CALLBACK CompletionROUTINE{
DWORD dwError, //指定lpOverlapped参数中表示的重叠操作的完成状态
DWORD cbTransferred, //传送完成的数据数量
LPWSAOVERLAPPED lpOverlapped, //指定重叠结构
DWORD dwFlags //指定操作结束时的标记,通常设置为0
};
(3)以面向连接额的数据接收为例
- 套接字初始化,设置为重叠I/O模式;
- 初始化重叠结构;
- 异步传输数据,将重叠结构作为输入参数,并指定一个完成例程对应于数据传输后的处理;
- 调用WSAWaitForMultipleEvents()或SleepEx(),将自己的线程设置为一种可警告等待状态,等待一个重叠I/O请求完成,重叠请求完成后,完成例程会自动执行,在完成例程内,可随一个完成例程一起投递另一个重叠I/O操作;
- 回到步骤3。
4、重叠I/O模型评价
- 应用程序中的I/O操作<-->重叠结构<-->事件
- 使应用程序能达到更佳的系统性能
- 减少了一次从I/O缓冲区到应用程序缓冲区的拷贝。
如有错误,敬请指正。
您的收藏与点赞都是对我最大的鼓励和支持!