Windows套接字I/O模型

来源:互联网 发布:mmd双人动作数据下载 编辑:程序博客网 时间:2024/06/03 07:57

两中模式执行I/O操作
阻塞模式:执行I/O的Winsock调用(如send和recv),一直到操作完成才返回。
非阻塞模式:Winsock函数会立即返回

1.select(选择)模型
1>增加一个套接字集合fd
2>设置一个可读或者可写的套接字集合fd1
3>使用select函数(可设置等待的时长)获得有I/O操作的套接字集合fd1
4>处理这些I/O

可以理解为:假设有10个快递要取,我隔断时间就去快递站去看有没有我的快递,如果有我就拿回来,如果没有我也立刻回来,重复如此。

2.WSAAsyncSelect模型(异步选择模型)(需要建立一个窗口用于接收消息)
以windows消息的形式接收网络事件通知
可以理解为:我不需要隔段时间就去看快递有没有到,如果快递到了,快递公司打电话给我,我再去拿快递

3.WSAEventSelect模型(事件选择模型)
接受网络事件,不是依靠Windows消息驱动机制,而是经由事件对象句柄通知
1>创建一个事件句柄表和一个对应的套接字句柄表
2>每创建一个套接字就创建一个事件对象,把它们的句柄分别放入到上面的两个表中,并调用WSAEventSelect添加它们的关联
3>调用WSAWaitForMultipleEvents在所有事件对象上等待,以便确认哪些套接字上发生了网络事件
4>处理发生的网络事件,继续在事件对象上等待

可以理解为:有点类似WSAAsyncSelect模型,但是它不需要消息通知,它将套接字和网络事件及事件对象绑定了在一起。就相当于我在快递站安装了一个监测器,如果快递到了,检测器就会发出通知,就不用快递公司一个一个的打电话。

4.重叠(Overlapped)I/O模型
由于读写操作太慢,应用程序不想等待,可以设置一个缓冲区,让操作系统完成读写操作,等完成了再来通知应用程序
可以理解为:快递公司直接将快递送到我家门口,到我家了再通知我开门签收,误区自己去快递公司

5.完成端口模型(iocp)
IOCP采用了线程池(提前创建好线程,更有效)+队列+重叠结构的内核机制完成任务
1>创建完成端口对象
2>创建一个或者多个工作线程(I/O服务线程)
3>将套接字关联到完成端口对象
4>套接字向完成端口提交各种所需请求
5>在完成端口上等待的线程池处理这些I/O

#include"CInitSock.h"CInitSock init;#define BUFFER_SIZE 1024typedef struct _PER_HANDLE_DATA{    SOCKET s;    sockaddr_in addr;}PER_HANDLE_DATA,*PPER_HANDLE_DATA;typedef struct _PER_IO_DATA{    OVERLAPPED ol;    char buf[BUFFER_SIZE];    int nOperationType;#define OP_READ 1#define OP_WRITE 2#define OP_ACCEPT 3}PER_IO_DATA, *PPER_IO_DATA;DWORD WINAPI ServerThread(LPVOID lpParam);int main(){    int nPort = 4567;    HANDLE hCompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);    CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);    SOCKET sListen = socket(AF_INET, SOCK_STREAM, 0);    SOCKADDR_IN si;    si.sin_family = AF_INET;    si.sin_port = ntohs(nPort);    si.sin_addr.S_un.S_addr = INADDR_ANY;    bind(sListen, (sockaddr*)&si, sizeof(si));    listen(sListen, 5);    while (TRUE)    {        SOCKADDR_IN saRemote;        int nRemoteLen = sizeof(saRemote);        SOCKET sNew = accept(sListen, (sockaddr*)&saRemote, &nRemoteLen);        cout << "接收到" <<inet_ntoa(saRemote.sin_addr) << "的连接" << endl;        PPER_HANDLE_DATA  pPerHandle = (PPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));        pPerHandle->s=sNew;        memcpy(&pPerHandle->addr, &saRemote, nRemoteLen);        CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);        PPER_IO_DATA pPerIO = (PPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));        pPerIO->nOperationType = OP_READ;        WSABUF buf;        buf.buf = pPerIO->buf;        buf.len = BUFFER_SIZE;        DWORD dwRecv;        DWORD dwFlags = 0;        WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);    }}DWORD WINAPI ServerThread(LPVOID lpParam){    HANDLE hCompletion = (HANDLE)lpParam;    DWORD dwTrans;    PPER_HANDLE_DATA pPerHandle;    PPER_IO_DATA pPerIO;    while (TRUE)    {        BOOL bOK = GetQueuedCompletionStatus(hCompletion, &dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);        if (!bOK)        {            closesocket(pPerHandle->s);            GlobalFree(pPerHandle);            GlobalFree(pPerIO);            continue;        }        if (dwTrans == 0 && (pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))        {            closesocket(pPerHandle->s);            GlobalFree(pPerHandle);            GlobalFree(pPerIO);            continue;        }        switch (pPerIO->nOperationType)        {        case OP_READ:        {                        pPerIO->buf[dwTrans] = '\0';                        cout << inet_ntoa(pPerHandle->addr.sin_addr) << ":";                        cout << pPerIO->buf<<endl;                        WSABUF buf;                        buf.buf = pPerIO->buf;                        buf.len = BUFFER_SIZE;                        pPerIO->nOperationType = OP_READ;                        DWORD nFlags = 0;                        WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);        }            break;        case OP_WRITE:            case OP_ACCEPT:break;        }    }    return 0;}
原创粉丝点击