基于WSAEventSelect异步 I / O模型socket服务器的主要代码

基于WSAEventSelect异步 I / O模型的TCP/IP流式套接字服务器具体实现主要分为下面两个步骤。

1 首先创建流式套接字。代码如下:

WSAData ws;
    sockaddr_in    addr;
    WSAStartup(MAKEWORD(2, 2), &ws);
    SOCKET svrsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    addr.sin_family = PF_INET;
    addr.sin_addr.s_addr = inet_addr(SetInfor->sIp.c_str()); // 服务器IP转网络字节序
    addr.sin_port = htons(SetInfor->nPort); // 服务器端口转网络字节

    // 绑定套接字
    int nError = bind(svrsock, (sockaddr*)&addr, sizeof(addr));

    WSAEVENT newEvent = WSACreateEvent();

    WSAEventSelect(svrsock, newEvent, FD_ACCEPT | FD_CLOSE); // 只监听读和关闭

    // 监听套接字
    listen(svrsock, 5);

    m_sockets[m_nTotal] = svrsock;
    m_events[m_nTotal] = newEvent;
    ++m_nTotal;

    m_CHThread.Start(); // 开启线程以便访问流式套接字的网络事件方法

2    在线程函数中遍历套接字的网络事件方法,主要代码如下:

WSANETWORKEVENTS networkevent;
    while (!m_bExit)
    {
#if 0
        OutputDebugString(L"run!\n");
#endif

        CAutoLock autolock(&m_myLock);

        DWORD drindex = WSAWaitForMultipleEvents(m_nTotal, m_events, FALSE, 100, FALSE);//WSA_INFINITE
        // 加锁
        if (WSA_WAIT_TIMEOUT == drindex)
        {
            continue;
        }
        // 有网络事件

        WSAEnumNetworkEvents(
            m_sockets[drindex - WSA_WAIT_EVENT_0],
            m_events[drindex - WSA_WAIT_EVENT_0], // 自动重置未传信状态 
            &networkevent);
        if (networkevent.lNetworkEvents & FD_ACCEPT)
        {
            if (networkevent.iErrorCode[FD_ACCEPT_BIT] != 0)
            {
                char msg[100] = { 0 };
                sprintf_s(msg, 100, "FD_CONNECT Failed with error %d \n", networkevent.iErrorCode[FD_ACCEPT_BIT]);
                printf(msg);

                if (m_pTcpSvrNotifyInf)
                {
                    m_pTcpSvrNotifyInf->onAccept(-1);
                    for (int i = 0; i < m_nTotal; i++)
                    {
                        closesocket(m_sockets[i]);
                        WSACloseEvent(m_events[i]);
                    }
                    m_nTotal = 0;
                    m_CHThread.suspend(); // 暂停线程
                }
                continue;
            }

            sockaddr_in addr;
            int naddrLen = sizeof(addr); // 必须要赋实际值,不能为0,为0的话accept返回的socket就会有问题
            char msg[100] = { 0 };
#if 1
            SOCKET clisocket = accept(m_sockets[drindex - WSA_WAIT_EVENT_0], (PSOCKADDR)&addr, &naddrLen);
            string ip = inet_ntoa(addr.sin_addr);
            unsigned short port = ntohs(addr.sin_port);
            sprintf_s(msg, 100, "客户端信息: %s:%d \n", (char*)ip.c_str(), port);
            OutputDebugStringA(msg);
#else
            SOCKET clisocket = accept(m_sockets[drindex - WSA_WAIT_EVENT_0], NULL, NULL);
#endif
            if (m_nTotal >= WSA_MAXIMUM_WAIT_EVENTS)
            {
                sprintf_s(msg,100,"超过了最大的连接数64\n");
                OutputDebugStringA(msg);
                closesocket(clisocket);
                break;
            }
            WSAEVENT newEvent = WSACreateEvent();
            WSAEventSelect(clisocket, newEvent, FD_READ | FD_WRITE | FD_CLOSE); // 只监听读、写、关闭
            m_sockets[m_nTotal] = clisocket;
            m_events[m_nTotal] = newEvent;
            m_nTotal++;
            sprintf_s(msg, 100, "clisocket %d connected!\n", clisocket);
            OutputDebugStringA(msg);
            if (m_pTcpSvrNotifyInf)
            {
                m_pTcpSvrNotifyInf->onAccept(0);
            }
        }
        else if (networkevent.lNetworkEvents & FD_READ)
        {
            if (networkevent.iErrorCode[FD_READ_BIT] != 0)
            {
                char msg[100] = { 0 };
                sprintf_s(msg, 100, "FD_READ Failed with error %d \n", networkevent.iErrorCode[FD_READ_BIT]);
                printf(msg);
                OutputDebugStringA(msg);
               for (int i = 0; i < m_nTotal; i++)
                {
                    closesocket(m_sockets[i]);
                    WSACloseEvent(m_events[i]);
                }
                m_nTotal = 0;
                m_CHThread.suspend(); // 暂停线程
                continue;
            }
            char buf[4096] = { 0 };
            int nLen = recv(m_sockets[drindex - WSA_WAIT_EVENT_0], buf, 4096, 0);
            printf("收到的数据为:%s \n", buf);
            char msg[100] = { 0 };
            sprintf_s(msg, 100, "收到的数据为:%s nDataLen:%d \n", (char*)buf, nLen);
            string strmsg = msg;
            wstring wstrmsg;
            CCharactor::StringToWString(strmsg, wstrmsg);
            OutputDebugString(wstrmsg.c_str());
            string msgData = buf;
            string::size_type index = msgData.find(',');
            if (index != string::npos)
            {
                string strtempfile = msgData.substr(index + 1, msgData.length() - index);
                if (m_curtempfile.empty())
                {
                    m_curtempfile = strtempfile;
                }
                else
                {
                    if (0 == m_curtempfile.compare(strtempfile.c_str()))
                    {
                        char msg[200] = { 0 };
                        sprintf_s(msg, 200, "较上次收到的文件一致,直接退出(文件名:%s.ezd)", m_curtempfile.c_str());
                        unsigned char OkMsg[10] = { 0 };
                        sprintf_s((char*)OkMsg, 10, "randy");
                        send(m_sockets[drindex - WSA_WAIT_EVENT_0], (char*)OkMsg, strlen((char*)OkMsg), 0);
                        continue;
                    }
                    else
                    {
                        m_curtempfile = strtempfile;
                    }
                }
            }
            wstring wstr;
            CCharactor::StringToWString(m_curtempfile, wstr);
            CString cstr = wstr.c_str();

            if (m_pTcpSvrNotifyInf)
            {
                m_pTcpSvrNotifyInf->onUpdateData(cstr);
            }
        }
        else if (networkevent.lNetworkEvents & FD_WRITE)
        {
            OutputDebugStringA("可以开始发送数据了\n");
        }
        else if (networkevent.lNetworkEvents & FD_CLOSE)
        {
            if (networkevent.iErrorCode[FD_CLOSE_BIT] != 0)
            {
                char msg[100] = { 0 };
                sprintf_s(msg, 100, "FD_CLOSE Failed with error %d \n", networkevent.iErrorCode[FD_CLOSE_BIT]);
                printf(msg);
                OutputDebugStringA(msg);
                for (int i = 0; i < m_nTotal; i++)
                {
                    closesocket(m_sockets[i]);
                    WSACloseEvent(m_events[i]);
                }
                m_nTotal = 0;
                m_CHThread.suspend(); // 暂停线程

              break;


            }

            char msg[100] = { 0 };
            sprintf_s(msg, 100, "socket %d closed! index:%d\n", m_sockets[drindex - WSA_WAIT_EVENT_0], drindex - WSA_WAIT_EVENT_0);
            closesocket(m_sockets[drindex - WSA_WAIT_EVENT_0]);
            // 后面的往前移
            for (int i = drindex - WSA_WAIT_EVENT_0; i < m_nTotal-1; i++)
            {
                m_sockets[i] = m_sockets[i + 1];
            }
            m_nTotal--;
            printf(msg);
            OutputDebugStringA(msg);
            if (m_pTcpSvrNotifyInf)
                m_pTcpSvrNotifyInf->onClientClosed();
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值