尝试新思路——跨平台Select模型

Select模型头文件

#ifndef __SELECT_H__
#define __SELECT_H__

#define ERROR_SELECT_MAXFD    1
#define ERROR_SELECT_INVALID  2
#define ERROR_SELECT_SOCKET   3

namespace LinWin
{
    class CNetworkEvent;
    class CError;
    class CExit;

    class CSelectImpl
    {
    private:
        net_socket_fd m_fdListen;
        fd_set        m_fdSocket;

    public:
        explicit CSelectImpl(net_socket_fd fdListen);
        void SetListenFd(net_socket_fd fdListen);
        int Select(CNetworkEvent* pEvent, CError* pError, CExit* pExit);
    };
}

#endif

实现文件

#include "Platform.h"
#include "Select.h"
#include "NetworkEvent.h"
#include "Error.h"
#include "Exit.h"

#define MAX_CLIENT_NUM 16

LinWin::CSelectImpl::CSelectImpl(net_socket_fd fdListen) : m_fdListen(fdListen)
{
}

void LinWin::CSelectImpl::SetListenFd(net_socket_fd fdListen)
{
    if (m_fdListen == NET_INVALID_SOCKET)
        m_fdListen = fdListen;
}

int LinWin::CSelectImpl::Select(CNetworkEvent* pEvent, CError* pError, CExit* pExit)
{
    int ret;
    int i, j;
    int nClientCount = 1;
    fd_set fdReads;

    if (m_fdListen == NET_INVALID_SOCKET)
        return ERROR_SELECT_SOCKET;

    FD_ZERO(&m_fdSocket);
    FD_SET(m_fdListen, &m_fdSocket);

    if (!pEvent || !pError || !pExit)
        return ERROR_SELECT_INVALID;

    net_socket_fd client_fd[MAX_CLIENT_NUM];
    client_fd[0] = m_fdListen;
    for (int i = 1; i < MAX_CLIENT_NUM; i++)
        client_fd[i] = -1;

#ifndef WINDOWS_FAMILY
    int maxfd;
#endif

    while (1)
    {
        ret = 0;
        if (pExit->OnExit())
            break;
        fdReads = m_fdSocket;
#ifdef WINDOWS_FAMILY
        ret = ::select(0, &fdReads, NULL, NULL, NULL);
#else
        maxfd = m_fdListen;
        for(i = 0; i < MAX_CLIENT_NUM; i++)
        {
            if (maxfd < client_fd[i])
                maxfd = client_fd[i];
        }
        ret = ::select(maxfd + 1, &fdReads, NULL, NULL, NULL);
#endif

        if (ret > 0)
        {
            for (i = 0; i < MAX_CLIENT_NUM; i++)
            {
                if (FD_ISSET(client_fd[i], &fdReads))
                {
                    if (client_fd[i] == m_fdListen)
                    {
                        if (nClientCount < MAX_CLIENT_NUM)
                        {
                            net_socket_fd fdAccept = NET_INVALID_SOCKET;
                            pEvent->OnAccept(fdAccept);
                            if (fdAccept != NET_INVALID_SOCKET)
                            {
                                for (j = 1; j < MAX_CLIENT_NUM; j++)
                                {
                                    if (client_fd[j] == -1)
                                    {
                                        client_fd[j] = fdAccept;
                                        FD_SET(fdAccept, &m_fdSocket);
                                        nClientCount++;
                                        break;
                                    }
                                }
                            }                                   
                        }
                        else
                        {
                            pError->OnError(ERROR_SELECT_MAXFD, ELEVEL_WARNING);
                        }
                    }
                    else
                    {
                        if (pEvent->OnRead(client_fd[i]) != 0)
                        {
                            if (pEvent->OnClose(client_fd[i]) != 0)
                                closesocket(client_fd[i]);
                            FD_CLR(client_fd[i], &m_fdSocket);
                            client_fd[i] = -1;
                            nClientCount--;
                        }
                    }
                }
            }
        }
        else
        {
            if (pError->OnError(ELEVEL_ERROR) != 0)
                break;
        }
    }

    return ret;
}

测试文件main.cpp

#include <iostream>
#include "Platform.h"
#include "SocketImpl.h"
#include "MyError.h"
#include "MyExit.h"
#include "MySelectEvent.h"
#include "Select.h"
using namespace std;

int main(int argc, char* argv[])
{
    LinWin::CSocketAddress addr(NET_DEFAULT_IP, 6666);
    LinWin::CSocketImpl server;
    do
    {
        if (server.Create() != 0)
        {
            cout << "Create socket error." << endl;
            break;
        }
        if (server.Bind(addr) != 0)
        {
            cout << "Bind address errror." << endl;
            break;
        }
        if (server.Listen(2) != 0)
        {
            cout << "Listen error." << endl;
            break;
        }

        LinWin::CSelectImpl mySelect(server.Sockfd());
        CMyError myError;
        CMyExit myExit;
        CMySelectEvent mySelectEvent(&server, &myExit);
        mySelect.Select(&mySelectEvent, &myError, &myExit);
    } while (0);

    return 0;
}

测试程序给出的是服务器端的例子,客户端还可以用之前给出的客户端的例子。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值