网络编程之路---12


WSAEventSelect模型:(异步IO模型)以事件形式进行通知
int WSAEventSelect(SOCKET s, WSAEvent hEventObject, long lNetworkEvents)
套接字,                            与网络事件集合相关联的事件对象句柄,                   感兴趣的网络事件集合
基本流程:为感兴趣的网络事件集合创建一个事件对象,调用WSAEventSelect将网络事件和事件对象关联起来。当网络事件发生时,
winsock使响应的事件对象受信,在事件对象上等待的函数会立即返回。再调用WSAEnumNetworkEvents函数就可以获得到底发生了什么网络事件.

WSACreateEvent()
WSAResetEvent()
WSASetEvent()
WSACloseEvent()
WSAWaitForMultipEvents()
WSAEnumNetworkEvents()

#include <WinSock2.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

using namespace std;


int main()
{
    //事件句柄和套接字句柄

    WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];
    SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS];

    int nEventTotal = 0; //注册事件的总数
    USHORT nPort = 9990; //服务器端口号

    //初始化Winsockets环境
    WSADATA ws;
    WSAStartup(MAKEWORD(2,2), &ws);

    SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in sin;

    sin.sin_family = AF_INET;
    sin.sin_port = htons(nPort);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;


    if (::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        std::cout << "failed" << std::endl;
        return -1;
    }
    ::listen(sListen, 5);

    //创建事件对象
    WSAEVENT event = ::WSACreateEvent();
    ::WSAEventSelect(sListen, event, FD_ACCEPT | FD_CLOSE);
    
    //分别放到数组中
    eventArray[nEventTotal] = event;
    sockArray[nEventTotal] = sListen;
    nEventTotal++;


    while (true)
    {
        //在所有事件对象上等待
        int nIndex = ::WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE);
        //任一事件变成授信状态就返回 事件对象的句柄
        nIndex = nIndex - WSA_WAIT_EVENT_0; //发生的事件对象的索引

        //循环处理后面的事件对象
        for (int i = nIndex; i < nEventTotal; ++i)
        {
            int ret;
            ret = ::WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE);

            if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
            {
                continue;
            }
            else //表明有事件授信
            {
                WSANETWORKEVENTS event1;
                ::WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event1);
                if (event1.lNetworkEvents & FD_ACCEPT)
                {
                    if (nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
                    {
                        cout << "连接了好多的样子" << endl;
                        continue;
                    }
                    SOCKET sNew = ::accept(sListen, NULL, NULL); //不用关心客户端的地址,所以直接为空吧
                    
                    WSAEVENT wsaEvent = ::WSACreateEvent();
                    ::WSAEventSelect(sNew, wsaEvent, FD_READ | FD_WRITE | FD_CLOSE);
                    eventArray[nEventTotal] = wsaEvent;
                    sockArray[nEventTotal] = sNew;
                    nEventTotal++;
                }

                else if(event1.lNetworkEvents & FD_READ) //开始读东西了
                {
                    if (event1.iErrorCode[FD_READ_BIT] == 0)
                    {
                        char szText[256];
                        int nRecv = ::recv(sockArray[i], szText, strlen(szText), 0);

                        if (nRecv > 0)
                        {
                            szText[nRecv] = '\0';
                            cout << "提取到数据:" << szText << endl;
                            strcpy(szText, "数据已经收到");
                            int nSnd = ::send(sockArray[i], szText, strlen(szText), 0); //发送是非阻塞的,直接返回掉
                        }
                    }
                }
                else if (event1.lNetworkEvents & FD_CLOSE)
                {

                    //关闭socket了
                    if (event1.iErrorCode[FD_CLOSE_BIT] == 0)
                    {
                        ::closesocket(sListen);
                        for (int j = i; j < nEventTotal - 1; j++)
                        {
                            sockArray[j] = sockArray[j + 1]; //把这个socket从数组里删除掉,数组肯定要移动位置3
                            
                        }
                        nEventTotal--;
                    }
                }
                else if(event1.lNetworkEvents & FD_WRITE) //由服务端程序自身触发
                {
                    if (event1.iErrorCode[FD_WRITE_BIT] == 0)
                    {
                        char szText[256] = "嘿嘿,已经收到了哈";
                        int nSnd = ::send(sockArray[i], szText, strlen(szText), 0);
                    }
                }
            }
        }
    }
}

嘿嘿。如果是UDP的话(赶脚好高端的样子).就只监听FD_READ | FD_CLOSE了。。。。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值