4.3.4重叠I/O模型
异步IO和同步IO的区别:
同步IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行。
异步IO中,线程发送一个IO请求到内核,然后继续处理其他的事情,内核完成IO请求后,将会通知线程IO操作完成了。重叠IO属于异步IO。
在Windows socket中,接收数据分为2步:等待数据传输;将数据从系统复制到用户空间。
第一阶段(等待数据传输):select模型利用select函数主动检查系统中套接字是否满足可读条件;而WSAAsyncSelect模型和WSAEventSelect模型则被动等待系统的通知。
第二阶段:前三个模型在数据从系统复制到用户缓冲区时,线程阻塞(recv)。重叠IO的应用程序在调用输入函数(WSARecv)后继续执行,直到系统完成IO操作后发出通知。
总结:由于IO操作虽然耗时但并不占CPU资源,因此将IO操作交给操作系统来完成,等操作系统完成IO操作后,发送通知给应用程序。操作系统内部采用线程的方式来实现重叠IO,它可以同时接收多个客户端传来的数据。
重叠IO模型分为2种:事件通知、完成例程。
//重叠IO:事件通知TCP服务器端
#include <iostream>
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#pragma comment (lib, "Ws2_32.lib")
using namespace std;
#define PORT 6000
#define SIZE 1024
//创建单IO结构体
typedef struct
{
WSAOVERLAPPED overlap; //每一个socket连接需要关联一个WSAOVERLAPPED对象
WSABUF Buffer; //与WSAOVERLAPPED对象绑定的缓冲区
char szMessage[SIZE]; //初始化buffer的缓冲区
DWORD NumberOfBytesRecvd; //指定接收到的字符的数目
DWORD Flags;
}MY_WSAOVERLAPPED, *LPMY_WSAOVERLAPPED;
SOCKET g_ClientSocketArr[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT g_ClientEventArr[WSA_MAXIMUM_WAIT_EVENTS];
LPMY_WSAOVERLAPPED g_pWSAOVERLAPPED_Arr[WSA_MAXIMUM_WAIT_EVENTS];
int g_EvenCount = 0;
UINT WINAPI WorkerThread(LPVOID lpParameter);
int main(int argc,char ** argv)
{
//步骤1:当前应用程序和相应的socket库绑定
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
cout << "WSAStartup Failed!" << endl;
return -1;
}
//步骤2:创建监听套接字和服务器端IP/PORT
//SOCKET sockListen = WSASocket(AF_INET, SOCK_STREAM, 0,NULL,0, WSA_FLAG_OVERLAPPED);
SOCKET sockListen = socket(AF_INET, SOCK_STREAM