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;
}

 

posted @ 2016-07-31 13:00  你好阿汤哥  Views(4672)  Comments(0Edit  收藏  举报