您的位置:首页 > 编程语言 > C语言/C++

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

2016-07-31 13:00 295 查看
说明:当客户端连接数超过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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: