C++ Windows 上简单的非阻塞Select模型

说明:当客户端连接数超过64个的时候,每次最多select64个,但每一帧可以select多次,理论上可以突破fd个数的限制

.h

#ifndef _MODULE_SELECT_H_
#define _MODULE_SELECT_H_
#include "platform/platform.h"

class CModuleSelect
{
public:
    CModuleSelect();
    ~CModuleSelect();
public:
    int32_t Initialize();
    int32_t Uninitialize();
    void ProcessEvent(uint32_t nTimeUsec);
public:
    int32_t AddFd(int32_t fd);
    int32_t DelFd(uint32_t index);
protected:
    void FDSet(int32_t fd)
    {
        FD_SET(fd, &readfds); FD_SET(fd, &writefds); FD_SET(fd, &errorfds);
        if (fd + 1 > maxfdp){ maxfdp = fd + 1; }
    }
    void FDZero()
    {
        FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds);
        maxfdp = 0;
    }
    void FDClear(int32_t fd)
    {
        FD_CLR(fd, &readfds); FD_CLR(fd, &writefds); FD_CLR(fd, &errorfds);
    };
private:
    int32_t sListen;
    // fd_set for select
    int32_t maxfdp;
    struct fd_set readfds, writefds, errorfds;
    // all used fd
    uint32_t unFdSize;
    int32_t *arrFd;
};

#endif

.cpp

#include "module_select.h"
#include "common/common.h"

CModuleSelect::CModuleSelect()
{
    unFdSize = 0;
    arrFd = new int32_t[unMaxFdSize];
}

CModuleSelect::~CModuleSelect()
{
    Uninitialize();
}

int32_t CModuleSelect::Initialize()
{
    WSADATA     wsaData;
    int32_t nRet = WSAStartup(0x0202, &wsaData);
    if (nRet != S_OK){ return WSAGetLastError(); }
    sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    nRet = AddFd(sListen);
    if (nRet != S_OK){ return nRet; }

    SOCKADDR_IN addrLocal;
    addrLocal.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    addrLocal.sin_family = AF_INET;
    addrLocal.sin_port = htons(nPort);

    // bind
    nRet = bind(sListen, (struct sockaddr*)&addrLocal, sizeof(SOCKADDR_IN));
    if (nRet != S_OK){ return WSAGetLastError(); }

    // listen
    nRet = listen(sListen, 5);
    if (nRet != S_OK){ return WSAGetLastError(); }
    printf("listen:%d\n", sListen);
    return S_OK;
}

void CModuleSelect::ProcessEvent(uint32_t nTimeUsec)
{
    int32_t nRet = S_OK;
    static struct timeval timeout;
    timeout.tv_sec = nTimeUsec / 1000000;
    timeout.tv_usec = nTimeUsec % 1000000;

    static int32_t addrSize = sizeof(SOCKADDR_IN);
    static char buf[1024];
    static SOCKADDR_IN addrRemote;
    // select all used fd
    uint32_t unStartPos = 0, unEndPos = 0;
    do
    {
        // reset fd_set
        FDZero();
        // fd_set size limited by ‘FD_SETSIZE‘
        for (uint32_t i = 0; i < FD_SETSIZE && unEndPos < unFdSize; ++i)
        {
            FDSet(arrFd[unEndPos++]);
        }
        nRet = select(maxfdp, &readfds, &writefds, &errorfds, &timeout);
        // select error
        if (nRet == -1)
        {
            int32_t nError = WSAGetLastError();
            perrors("select error,nRet=%d,info=%s\n", nError, strerror(nError));
            exit(1);
        }
        // time out ,nothing happened
        else if (nRet == 0)
        {
            printf(".");
            continue;
        }
        // some thing happened
        else if (nRet > 0)
        {
            // check events
            for (uint32_t i = unStartPos; i < unEndPos; ++i)
            {
                // read events
                if ( FD_ISSET(arrFd[i],&readfds) )
                {
                    printf("[%d]:read = %d\n",i,arrFd[i]);
                    if (sListen == arrFd[i])
                    {
                        nRet = accept(sListen, (struct sockaddr*)&addrRemote, &addrSize);
                        printf("Accepted client:%s:%d\n", inet_ntoa(addrRemote.sin_addr), ntohs(addrRemote.sin_port));
                        AddFd(nRet);
                    }
                    else
                    {
                        nRet = recv(arrFd[i], buf, 1024, 0);
                        if (nRet == 0 || nRet == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
                        {
                            // client close
                            DelFd(i);
                        }
                        else
                        {
                            // received correct data from client
                            buf[nRet] = ‘\0‘;
                            send(arrFd[i], buf, strlen(buf), 0);
                        }
                    }
                }
                // write events
                else if (FD_ISSET(arrFd[i], &writefds))
                {
                    Sleep(1);
                    //printf("write = %d\n", arrFd[i]);
                }
                // error events
                else if (FD_ISSET(arrFd[i], &errorfds))
                {
                    printf("error = %d\n", arrFd[i]);
                }
            }
        }
        // for next loop
        unStartPos = unEndPos;
    }while (unEndPos < unFdSize);
}

int32_t CModuleSelect::Uninitialize()
{
    return WSACleanup();
}

int32_t CModuleSelect::AddFd(int32_t fd)
{
    if (unFdSize < unMaxFdSize)
    {
        arrFd[unFdSize++] = fd;
        return S_OK;
    }
    return -1;
}

int32_t CModuleSelect::DelFd(uint32_t index)
{
    if (unFdSize > 1 && index > 0 && unFdSize > index)
    {
        closesocket(arrFd[index]);
        arrFd[index] = arrFd[unFdSize - 1];
        --unFdSize;
    }
    return S_OK;
}
时间: 2024-11-12 23:00:47

C++ Windows 上简单的非阻塞Select模型的相关文章

python 简单搭建非阻塞式单进程,select模式,epoll模式服务

由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 :  --> 点击这里 1 单进程服务器 - 非堵塞模式 服务端 : #coding=utf-8 from socket import * import time #用来存储所有的新连接的socket,这个是重点 g_socketList = [] def main(): serSocket = socket(AF_INET, SOCK_STREAM) serSocket.setsockopt(SO

CAS(Central Authentication Service)——windows上简单搭建及測试

入手文章,大神绕行. 一.服务端搭建 我使用的服务端版本号为:cas-server-3.4.11-release.zip.解压之后,将\cas-server-3.4.11-release\cas-server-3.4.11\modules\cas-server-webapp-3.4.11.war文件改名为cas.war,放置到tomcat的Tomcat\webapps文件夹下,之后启动tomcat. 之后进入*****\Tomcat\webapps\cas文件夹,改动两个配置文件: 1.改动To

CAS(Central Authentication Service)——windows上简单搭建及测试

入手文章,大神绕行. 一,服务端搭建 我使用的服务端版本为:cas-server-3.4.11-release.zip.解压之后,将\cas-server-3.4.11-release\cas-server-3.4.11\modules\cas-server-webapp-3.4.11.war文件改名为cas.war,放置到tomcat的Tomcat\webapps目录下,之后启动tomcat. 之后进入*****\Tomcat\webapps\cas文件夹,修改两个配置文件: 1,修改Tomc

python 之网络并发(非阻塞IO模型)

实现gevent模块 服务端: from socket import * import time s = socket() s.bind(('127.0.0.1',8080)) s.listen(5) s.setblocking(False) r_list=[] w_list=[] while True: try: conn, addr = s.accept() r_list.append(conn) except BlockingIOError: # time.sleep(0.05) prin

socket阻塞与非阻塞,同步与异步、I/O模型,select与poll、epoll比较

1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步:      异步的概念和同步相对.当c端一个异步过程调用发出后,调

Windows I/O模型、同步/异步、阻塞/非阻塞(转载)

转载自:http://www.cppblog.com/tx7do/articles/5954.html 同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等).但是一般而言,我们在说同步.异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务.最常见的例子就是 SendMessage.该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回.当对方处理完毕以后,该函数才把消息处理

非阻塞io模型和io多路复用----select

一.四种io阻塞1.io阻塞:(1 等待数据处于阻塞状态(2从内核copy到用户态处于阻塞状态2.非io阻塞只有从内核copy到用户态处于阻塞状态3.io多路复用----->优势:可以同时监听多个对象(1从check----->ready 通过selec函数来做,处于阻塞状态(2从内核copy到用户态处于阻塞状态3.异步io不用阻塞二.io多路复用select  poll epoll 都属于io同步里面的io多路复用select:轮询问题,监听数量有限poll:提高了监听数量epoll:解决了

socket阻塞与非阻塞,同步与异步、I/O模型

socket阻塞与非阻塞,同步与异步 作者:huangguisu 1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式:同步:      所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步:      异步的概念和同步相对

聊聊阻塞与非阻塞、同步与异步、I/O模型

1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端:  同步: 所谓同步,就是在c端发出一个功能调用时,在没有得到结果之前,该调用就不返回.也就是必须一件一件事做,等前一件做完了才能做下一件事. 例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事 异步: 异步的概念和同步相对.当c端一个异步过程调用发出后,调用者不能立刻得到结