Windows套接字I/O模型

本文介绍了五种网络编程中的I/O模型,包括select模型、WSAAsyncSelect模型、WSAEventSelect模型、重叠I/O模型和完成端口模型(iocp)。通过对比和示例说明了不同模型的特点及其应用场景。

两中模式执行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 1024
typedef 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值