// 通用库
namespace Common
{
// EpollSocket.h
namespace Thread
{
class CEpollSocket
{
public:
CEpollSocket();
virtual ~CEpollSocket();
public:
static const int FD_EXIT = -1; // 通知退出FD
static const int WAIT_NUM = 32; // 等待数量
static const int LISTEN_NUM = 32; // 监听数量
static const int BUFF_LEN = 4096; // 接收缓冲区大小
static const int EPL_CRT_NUM = 256; // EPOLL创建数量
public:
// 接收数据结构
struct SocketData
{
int fdSocket;
string strAddr;
unsigned int nSize;
char buff[BUFF_LEN];
};
typedef const SocketData* const PSocketData;
typedef void(*CallBackFunc)(void* const, PSocketData);
public:
// 创建服务
bool Open(const std::string& strIP, unsigned int nPort = 0);
// 运行服务
bool Run(bool *bExit, unsigned int nThreadNum = 1);
// 设置回调参数句柄
void SetHandle(void* const pHandle);
// 设置数据接收回调函数
void SetDataRecv(CallBackFunc const pFunc);
// 设置客户端连接回调函数
void SetCltConnect(CallBackFunc const pFunc);
// 设置客户端断开连接回调函数
void SetCltDisConnect(CallBackFunc const pFunc);
private:
// 私有化拷贝赋值构造函数,禁止实例复制
CEpollSocket(const CEpollSocket&);
CEpollSocket& operator =(const CEpollSocket&);
// 设置为非阻塞模式
bool SetNonBlocking(int fdSocket);
// 读书数据线程函数
static void* ReadData(void* pParam);
private:
int m_fdEpoll; // EPOLL句柄
int m_fdListen; // 监听句柄
void* m_pHandle; // 回调参数句柄
Thread::CThreadBuffer<int> m_fdBuff; // 客户端读取句柄缓冲区
CallBackFunc m_pOnDataRecv; // 接收数据回调函数
CallBackFunc m_pOnCltConnect; // 客户端连接回调函数
CallBackFunc m_pOnCltDisConnect; // 客户端断开连接回调函数
};
typedef CEpollSocket::PSocketData PSocketData;
}
// EpollSocket.cpp
namespace Net
{
extern const int CEpollSocket::FD_EXIT;
CEpollSocket::CEpollSocket()
{
m_fdEpoll = 0;
m_fdListen = 0;
m_pHandle = NULL;
m_pOnDataRecv = NULL;
m_pOnCltConnect = NULL;
m_pOnCltDisConnect = NULL;
}
CEpollSocket::~CEpollSocket()
{
//dtor
}
//
//【函数说明】: 设置为非阻塞模式
//【输入参数】: fdSocket 通讯句柄
//【输出参数】:
//【返回值】: true 成功;false 失败
//
bool CEpollSocket::SetNonBlocking(int fdSocket)
{
int iOpts = 0;
iOpts = fcntl(fdSocket, F_GETFL);
if (iOpts < 0)
{
std::cerr << "fcntl F_GETFL fail" << std::endl;
return false;
}
iOpts = iOpts | O_NONBLOCK;
if (fcntl(fdSocket, F_SETFL, iOpts) < 0)
{
std::cerr << "fcntl F_SETFL fail" << std::endl;
return false;
}
return true;
}
//
//【函数说明】: 创建服务
//【输入参数】: strIP IP地址;nPort 端口号
//【输出参数】:
//【返回值】: true 成功;false 失败
//
bool CEpollSocket::Open(const std::string& strIP, unsigned int nPort)
{
struct epoll_event epEvent;
struct sockaddr_in addrSrv;
m_fdEpoll = epoll_create(EPL_CRT_NUM);
m_fdListen = socket(AF_INET, SOCK_STREAM, 0);
if (m_fdEpoll < 1 || m_fdListen < 1)
{
std::cerr << "epoll_create or socket fail" << std::endl;
return false;
}
// 把socket设置为非阻塞方式
if (!SetNonBlocking(m_fdListen))
{
return false;
}
// 设置与要处理的事件相关的文件描述符
epEvent.data.fd = m_fdListen;
// 设置要处理的事件类型
epEvent.events = EPOLLIN | EPOLLET;
// 注册epoll事件
if (epoll_ctl(m_fdEpoll, EPOLL_CTL_ADD, m_fdListen, &epEvent) < 0)
{
std::cerr << "epoll_ctl fail" << std::endl;
return false;
}
// 设置服务地址信息
bzero(&addrSrv, sizeof(addrSrv));
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(nPort);
if (strIP.empty())
{
addrSrv.sin_addr.s_addr = INADDR_ANY;
}
else
{
addrSrv.sin_addr.s_addr = inet_addr(strIP.c_str());
}
// 绑定地址
if (bind(m_fdListen, (sockaddr*)&addrSrv, sizeof(addrSrv)) < 0)
{
std::cerr << "bind fail" << std::endl;
return false;
}
// 开始监听
if (listen(m_fdListen, LISTEN_NUM) < 0)
{
std::cerr << "listen fail" << std::endl;
return false;
}
return true;
}
//
//【函数说明】: 运行服务
//【输入参数】: bExit 退出标志;nThreadNum 读数据线程数量
//【输出参数】:
//【返回值】: true 成功;false 失败
//
bool CEpollSocket::Run(bool *bExit, unsigned int nThreadNum)
{
pthread_t* pThReadData = new pthread_t[nThreadNum];
// 启动读数据线程
for (unsigned int i = 0; i < nThreadNum; i++)
{
if (pthread_create(&pThReadData[i], NULL, ReadData, this) != 0)
{
std::cerr << "pthread_create fail" << std::endl;
goto Exit;
}
}
while (!*bExit)
{
unsigned int nFds = 0;
struct epoll_event epEvents[WAIT_NUM];
// 等待事件发生
nFds = epoll_wait(m_fdEpoll, epEvents, WAIT_NUM, -1);
// 处理所发生的所有事件
for (unsigned int i = 0; i < nFds; ++i)
{
// 有新客户端连接
if (epEvents[i].data.fd == m_fdListen)
{
int fdClient = 0;
struct sockaddr_in addrClt;
struct epoll_event epEvent;
socklen_t nAddrSize = sizeof(addrClt);
fdClient = accept(m_fdListen, (sockaddr*)&addrClt, &nAddrSize);
if (fdClient < 0)
{
std::cerr << "accept fail" << std::endl;
return false;
}
// 把socket设置为非阻塞方式
if (!SetNonBlocking(fdClient))
{
return false;
}
// 设置用于读操作的文件描述符、注测的读操作事件
epEvent.data.fd = fdClient;
epEvent.events = EPOLLIN | EPOLLET;
// 注册事件
if (epoll_ctl(m_fdEpoll, EPOLL_CTL_ADD, fdClient, &epEvent) < 0)
{
return false;
}
// 通知客户端连接
if (NULL != m_pOnCltConnect)
{
SocketData socketData;
socketData.fdSocket = fdClient;
socketData.strAddr = inet_ntoa(addrClt.sin_addr);
m_pOnCltConnect(m_pHandle, &socketData);
}
}
else if (epEvents[i].events & EPOLLIN)
{
m_fdBuff.Push(epEvents[i].data.fd);
}
}
}
Exit:
// 通知读取线程退出
for (unsigned int i = 0; i < nThreadNum; i++)
{
m_fdBuff.Push(FD_EXIT);
pthread_join(pThReadData[i], NULL);
}
delete[] pThReadData;
return true;
}
//
//【函数说明】: 设置回调参数句柄
//【输入参数】: pHandle 回调参数句柄
//【输出参数】:
//【返回值】:
//
void CEpollSocket::SetHandle(void* const pHandle)
{
m_pHandle = pHandle;
}
//
//【函数说明】: 设置数据接收回调函数
//【输入参数】: pHandle 数据接收回调函数
//【输出参数】:
//【返回值】:
//
void CEpollSocket::SetDataRecv(CallBackFunc const pFunc)
{
m_pOnDataRecv = pFunc;
}
//
//【函数说明】: 设置客户端连接回调函数
//【输入参数】: pHandle 客户端连接回调函数
//【输出参数】:
//【返回值】:
//
void CEpollSocket::SetCltConnect(CallBackFunc const pFunc)
{
m_pOnCltConnect = pFunc;
}
//
//【函数说明】: 设置客户端端口连接回调函数
//【输入参数】: pHandle 客户端端口连接回调函数
//【输出参数】:
//【返回值】:
//
void CEpollSocket::SetCltDisConnect(CallBackFunc const pFunc)
{
m_pOnCltDisConnect = pFunc;
}
//
//【函数说明】: 读书数据线程函数
//【输入参数】: pParam 类实例地址
//【输出参数】:
//【返回值】:
//
void* CEpollSocket::ReadData(void* pParam)
{
int nSize = 0;
SocketData socketData;
CEpollSocket* pEpollSocket = (CEpollSocket *)pParam;
while (true)
{
errno = 0;
memset(&socketData, 0, sizeof(socketData));
pEpollSocket->m_fdBuff.Pop(socketData.fdSocket);
if (socketData.fdSocket == FD_EXIT)
{
std::cout << "read data thread exit" << std::endl;
break;
}
// 循环接收数据
do
{
nSize = recv(socketData.fdSocket, socketData.buff + socketData.nSize, BUFF_LEN - socketData.nSize, 0);
if (nSize > 0)
{
socketData.nSize += nSize;
}
else
{
break;
}
} while (true);
// 判断是否为连接断开
if (socketData.nSize == 0 && errno != EINTR && errno != EAGAIN)
{
// 连接断开
struct epoll_event epEvent;
epEvent.data.fd = socketData.fdSocket;
epEvent.events = EPOLLIN | EPOLLET;
close(socketData.fdSocket);
epoll_ctl(pEpollSocket->m_fdEpoll, EPOLL_CTL_DEL, socketData.fdSocket, &epEvent);
// 通知客户端断开连接
if (NULL != pEpollSocket->m_pOnCltDisConnect)
{
pEpollSocket->m_pOnCltDisConnect(pEpollSocket->m_pHandle, &socketData);
}
continue;
}
// 回掉函数,通知处理数据
if (pEpollSocket->m_pOnDataRecv != NULL)
{
pEpollSocket->m_pOnDataRecv(pEpollSocket->m_pHandle, &socketData);
}
}
return NULL;
}
}
}
Epoll高并发通讯类
最新推荐文章于 2022-07-28 00:32:06 发布