zoukankan      html  css  js  c++  java
  • I/O模型

    如果要实现多个socket同时工作的话,

    一 . 同步阻塞 + 多线程

    二 . 同步非阻塞(ioctrlsocket):通俗讲,就是每个套接字都去内核看看收没收到消息,没收到再返回

    三 . I/O模型select:

          ①集合              fd_set

          ②清空集合            FD_ZERO

          ③将Socket放入集合内       FD_SET

          ④将集合交给select管理       select()

          ⑤校验数据(谁在集合中即收到数据)FD_ISSET

    优点:轮循查看集合内socket是否发生网络事件,将发生网络事件的socket留在集合内,简单方便跨平台

    缺点:有个数限制(最多处理64个,在winsock2.h定义的宏,我们可以重定义,但最多不超过1024),仍然为阻塞函数(查看,拷回数据)

    示例:

    bool UDPINet::SelectMySocket(SOCKET sock)
    {
        timeval tm;
        tm.tv_usec = 100;
        fd_set fd_sets;
        FD_ZERO(&fd_sets);
        FD_SET(sock,&fd_sets);
        select(NULL,&fd_sets,NULL,NULL,&tm);
        if(!FD_ISSET(sock,&fd_sets))//列表中没有套接字,则没收到消息,false
            return false;
        return true;
    }

    select函数的参数:

    四 . 异步选择(消息):当socket发生事件时发消息

             ①加载库

             ②socket

             ③bind

             ④创建窗口,注册(socket,事件,消息)WSAAsyncSelect()

    优点:阻塞时间短,只有拷贝数据时阻塞

    缺点:平台限制,只适用于Windows(因为它基于消息),时间消耗多(基于消息)

    示例:

        MyWnd = MyWnd->GetWnd();
        //创建窗口
        if(!MyWnd->Create(NULL,"MyWnd"))
        {
            UnInitInet();
            return false;
        }
        //注册
        WSAAsyncSelect(sock,*MyWnd,NM_MESSAGE,FD_READ);

    WSAAsyncSelect()的参数:

    其中MyWnd为新创建的窗口,用来接收NM_MESSAGE消息

    其中采用单例模型:懒汉模式:单线程

             饿汉模式:多线程

     五 . 异步事件(内核对象,操作系统通知)

    与异步消息不同:当socket发生事件时发事件

    单个socket情况:

        ws = WSACreateEvent();
        WSAEventSelect(sock,ws,FD_READ);

    线程实现函数:

       if(WAIT_TIMEOUT  == WaitForSingleObject(pthis->ws,100))
           continue;
       ResetEvent(pthis->ws);

    多个socket情况:将socket和event放入数组,下标相同则对应。

        WSAEVENT ws = WSACreateEvent();
        if(!WSAEventSelect(sock,ws,FD_READ))//成功返回零
        {
            aryevent[m_EvetNum] = ws;
            arysocket[m_EvetNum] = sock;
            m_EvetNum++;
        }
        thread = (HANDLE )_beginthreadex(NULL,0,&UDPINet::ThreadProc,this,0,0);

    线程函数:

            WSANETWORKEVENTS ws_network;
         DWORD  dwResult = WSAWaitForMultipleEvents(pthis->m_EvetNum,pthis->aryevent,FALSE,100,TRUE);
            if(WAIT_TIMEOUT == dwResult)
            {
                continue;
            }
            dwResult -= WSA_WAIT_EVENT_0 ;//获取事件索引
            //发生了什么类型的网络事件,成功返回0
            if(WSAEnumNetworkEvents(pthis->arysocket[dwResult],pthis->aryevent[dwResult],&ws_network))
                continue;
            if(ws_network.lNetworkEvents & FD_READ)//得到事件为可读消息
            {
                nRes = recvfrom(pthis->sock,buf,MAX_SIZE,0,(sockaddr*)&addr,&len);
                //调用处理函数
                if(nRes > 0)
                {
                    pthis->m_pIMeditor->DealMessage(buf,addr.sin_addr.S_un.S_addr);
                }
            }
  • 相关阅读:
    一条语句批量插入多条数据
    VMware Workstation 15 Pro 永久激活密钥
    windows下java项目打包、启动批处理 .bat文件
    java简写名词解释
    windows查看所有进程:netstat -ano
    Java验证jwt token
    【转载】三种方法从 HTTPS 网站导出 SSL 证书链
    使用solr将CSV/XML/DB/JSON数据发布为Rest Service
    检验多个xsd的xml是否合法
    Eclipse 打包运行maven项目
  • 原文地址:https://www.cnblogs.com/Lune-Qiu/p/8610148.html
Copyright © 2011-2022 走看看