##功能
1.支持1000+客户端链接
2.多线程处理:接收线程处理新连接,工作线程处理数据流动(可自行实现处理逻辑)
3.epoll机制
4.单例锁,互斥锁+条件变量
/*
* myreactor.h
*
* Created on: 2019-4-15
* Author: wlj
*/
#ifndef MYREACTOR_H_
#define MYREACTOR_H_
#include
//#include
#include
#include
#include
using namespace std;
#define WORKER_THREAD_NUM 5
class CMyReactor
{
public:
static CMyReactor* GetInstance()
{
pthread_once(&m_once,InitInstance);
return m_instance;
}
static void InitInstance()
{
m_instance = new CMyReactor();
}
~CMyReactor(void);
/*
功能:初始化
入参:ip:IP地址,nport:端口号
返回值:true/false
*/
bool Init(const char* ip, short nport);
/*
功能:循环epoll_wait()获取在线客户端个数,并判断ev[i].data.fd是链接线程还是工作线程,然后处理对应事件
入参:无
返回值:无
*/
void* MainLoop();
/*
功能:客户端退出
入参:clientfd:客户端fd
返回值:true/false
*/
bool DeleteClient(int clientfd);
/*
功能:服务端退出
入参:none
返回值:true/false
*/
bool ServiceExit();
protected:
CMyReactor(void);
CMyReactor(const CMyReactor&){};//禁止拷贝
// CMyReactor& operator=(const CMyReactor& reactor){return reactor;};//禁止赋值
static CMyReactor* m_instance;
private:
/*
功能:socket创建监听套接字listenfd,epoll_create(),往epoll事件表g_epollfd中注册listenfd上的事件
入参:ip:IP地址,nport:端口号
返回值:true/false
*/
bool CreateServerListener(const char* ip, short port);
/*
功能:获取客户端套接字newfd,往epoll事件表g_epollfd中注册newfd上的事件入参:reactor:MyReactor对象
返回值:none
*/
class GarbageCollector {
public:
~GarbageCollector() {
if (CMyReactor::m_instance) {
delete CMyReactor::m_instance;
CMyReactor::m_instance = 0;
}
}
};
bool isIPAddressValid(const char* pszIPAddr);
static GarbageCollector m_gc; //静态变量,只是为了释放单例
static void* AcceptThreadFunc(void *arg);
static pthread_once_t m_once;
int m_epollfd;
bool m_bStop;// 服务器停止
int m_listenfd;
pthread_cond_t m_acceptCond;
pthread_mutex_t m_acceptMutex;
pthread_t m_acceptThreadid;
pthread_t m_clientCheckid;
};
#endif /* MYREACTOR_H_ */
/*
* myreactor.cpp
*
* Created on: 2019-4-15
* Author: wlj
*/
#include"myreactor.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
//#include
#include
#include //for std::setw()/setfill()
#include
#include
#include "jobthread.h"
#include "easylog.h"
#include "../msgprocess/clientheartcheck.h"
#define min(a, b) ((a <= b) ? (a) : (b))
#define EPNUM 1024
#define LINSTENNUM 50
pthread_once_t CMyReactor::m_once = PTHREAD_ONCE_INIT;
CMyReactor*CMyReactor::m_instance = NULL;
CMyReactor::GarbageCollector CMyReactor::m_gc;
CMyReactor::CMyReactor()
{
m_listenfd = 0;
m_epollfd = 0;
m_acceptThreadid = 0;
m_clientCheckid = 0;
m_bStop = false;
}
CMyReactor::~CMyReactor()
{
}
bool CMyReactor::Init(const char* ip, short nport)
{
//IP 端口号合法性判断
if( !isIPAddressValid(ip))
{
LOG_ERROR("CMyReactor::Init::ip illegal!\n");
return false;
}
if(nport >= 65535)
{
LOG_ERROR("CMyReactor::Init::port >= 65535!\n");
return false;
}
LOG_INFO("CMyReactor::init:: begin! \n");
if(!CreateServerListener(ip,nport))
{
LOG_ERROR("Unable to bind:%d,nport:%d\n",ip,nport);
return false;
}
::pthread_cond_init(&m_acceptCond, NULL);
::pthread_mutex_init(&m_acceptMutex, NULL);
::pthread_create(&m_acceptThreadid,NULL,AcceptThreadFunc,NULL);
LOG_INFO("CMyReactor::init:: end! \n");
return true;
}
void*CMyReactor::MainLoop(void)
{
LOG_INFO("CMyReactor::MainLoop:: begin! \n");
LOG_INFO("main thread id = %u \n", pthread_self());
while(!m_bStop)
{
struct epoll_event ev[EPNUM];
int epClientNum = ::epoll_wait(m_epollfd,ev,EPNUM,5);
if(0 == epClientNum)
{
continue;
}
else if( 0 > epClientNum)
{
LOG_ERROR("epoll_wait error.\n");
continue;
}
int minEpNum = min(epClientNum,EPNUM);
LOG_INFO("minEpNum:%d\n",minEpNum);
for(int i = 0; i< minEpNum; i++)
{
if(ev[i].data.fd == m_listenfd)
{
pthread_cond_signal(&m_acceptCond);
}
else
{
//处理接收到的数据
//AddTaskToThreadPool(&(ev[i].data.fd));
}
}
}
LOG_INFO("CMyReactor::MainLoop:: end! \n");
return NULL;
}
bool CMyReactor::DeleteClient(int clientfd)
{
LOG_INFO("CMyReactor::DeleteClient begin \n");
::pthread_mutex_lock(&m_acceptMutex);
if (-1 == ::epoll_ctl( m_epollfd, EPOLL_CTL_DEL, clientfd, NULL) )
{
LOG_ERROR("CMyReactor::DeleteClient:: epoll_ctl EPOLL_CTL_DEL clientfd = %d failed\n",clientfd);
::pthread_mutex_unlock(& m_acceptMutex);
return false;
}
::pthread_mutex_unlock(& m_acceptMutex);
LOG_INFO("CMyReactor::DeleteClient clientfd = %d \n",clientfd);
LOG_INFO("CMyReactor::DeleteClient end \n");
::close(clientfd);
return true;
}
bool CMyReactor::ServiceExit()
{
LOG_INFO("CMyReactor::ServiceExit::begin! \n");
m_bStop = true;
if(-1 == ::epoll_ctl(m_epollfd, EPOLL_CTL_DEL, m_listenfd, NULL))
{
LOG_ERROR("CMyReactor::ServiceExit:: m_listenfd exit fail!\n");
return false;
}
::shutdown(m_listenfd, SHUT_RDWR);
::close(m_listenfd);
::close(m_epollfd);
::pthread_cond_destroy(&m_acceptCond);
::pthread_mutex_destroy(&m_acceptMutex);
LOG_INFO("CMyReactor::ServiceExit::end! \n");
return true;
}
bool CMyReactor::CreateServerListener(const char* ip, short port)
{
LOG_INFO("CMyReactor::CreateServerListener::begin! \n");
//IP合法性校验,端口号<65535
if( !isIPAddressValid(ip))
{
LOG_ERROR("CMyReactor::CreateServerListener::ip illegal!\n");
return false;
}
if(port >= 65535)
{
LOG_ERROR("CMyReactor::CreateServerListener::port >= 65535!\n");
return false;
}
m_listenfd = ::socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,0);
if(-1 == m_listenfd)
{
LOG_ERROR("CMyReactor::CreateServerListener::socket fail!\n");
return false;
}
LOG_INFO("m_listenfd =%d \n",m_listenfd);
int iButtomOn = 1;
::setsockopt(m_listenfd,SOL_SOCKET,SO_REUSEADDR,(char *)&iButtomOn,sizeof(iButtomOn));
::setsockopt(m_listenfd,SOL_SOCKET,SO_REUSEPORT,(char *)&iButtomOn,sizeof(iButtomOn));
struct sockaddr_in servaddr;
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family = AF_INET;//IPv4
servaddr.sin_addr.s_addr = inet_addr(ip);
servaddr.sin_port = htons(port);
if(-1 == ::bind(m_listenfd,(sockaddr*)&servaddr,sizeof(servaddr)) )
{
LOG_ERROR("CMyReactor::CreateServerListener::bind fail!\n");
return false;
}
if(-1 == ::listen(m_listenfd,LINSTENNUM))
{
LOG_ERROR("CMyReactor::CreateServerListener::listen fail!\n");
return false;
}
m_epollfd = epoll_create(1);
if(-1 == m_epollfd)
{
LOG_ERROR("CMyReactor::CreateServerListener::epoll_create fail!\n");
return false;
}
struct epoll_event e;
memset(&e,0,sizeof(e));
e.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
e.data.fd = m_listenfd;
if(-1 == ::epoll_ctl(m_epollfd,EPOLL_CTL_ADD,m_listenfd,&e))
{
LOG_ERROR("CMyReactor::CreateServerListener::epoll_ctl EPOLL_CTL_ADD m_listenfd = %d fail!\n",m_listenfd);
return false;
}
LOG_INFO("epoll_ctl EPOLL_CTL_ADD m_listenfd = %d success!\n",m_listenfd);
LOG_INFO("CMyReactor::CreateServerListener::end! \n");
return true;
}
void* CMyReactor::AcceptThreadFunc(void *arg)
{
LOG_INFO("CMyReactor::AcceptThreadFunc thread_id = %d \n",m_instance->m_acceptThreadid);
while(!m_instance-> m_bStop)
{
::pthread_mutex_lock(&m_instance->m_acceptMutex);
::pthread_cond_wait(&m_instance->m_acceptCond,&m_instance-> m_acceptMutex);
struct sockaddr_in clientaddr;
socklen_t addrlen;
int newClientfd = ::accept(m_instance->m_listenfd,(struct sockaddr*)&clientaddr,&addrlen);
if(-1 == newClientfd)
{
LOG_ERROR("CMyReactor::AcceptThreadFunc::accept newClientfd fail\n");
continue;
}
LOG_INFO("CMyReactor::AcceptThreadFunc new client = %d,connected:%s:%d \n",newClientfd,::inet_ntoa(clientaddr.sin_addr),::ntohs(clientaddr.sin_port));
int oldflag = ::fcntl(newClientfd, F_GETFL,0);
int newflag = oldflag | O_NONBLOCK;
if(-1 == ::fcntl(newClientfd,F_SETFL,newflag))
{
LOG_ERROR("CMyReactor::AcceptThreadFunc::fcntl error, oldflag = %d,newflag = %d\n",oldflag,newflag);
continue;
}
struct epoll_event e;
memset(&e,0,sizeof(e));
e.events = EPOLLIN | EPOLLRDHUP | EPOLLET;
e.data.fd = newClientfd;
if(-1 == ::epoll_ctl(m_instance->m_epollfd, EPOLL_CTL_ADD, newClientfd, &e))
{
LOG_ERROR("CMyReactor::AcceptThreadFunc::epoll_ctl error, fd = %d\n",newClientfd);
}
::pthread_mutex_unlock(&m_instance->m_acceptMutex);
}
return NULL;
}
bool CMyReactor::isIPAddressValid(const char* pszIPAddr)
{
if (!pszIPAddr) return false; //若pszIPAddr为空
char IP1[100],cIP[4];
int len = strlen(pszIPAddr);
int i = 0,j=len-1;
int k, m = 0,n=0,num=0;
//去除首尾空格(取出从i-1到j+1之间的字符):
while (pszIPAddr[i++] == ' ');
while (pszIPAddr[j--] == ' ');
for (k = i-1; k <= j+1; k++)
{
IP1[m++] = *(pszIPAddr + k);
}
IP1[m] = '\0';
char *p = IP1;
while (*p!= '\0')
{
if (*p == ' ' || *p<'0' || *p>'9') return false;
cIP[n++] = *p; //保存每个子段的第一个字符,用于之后判断该子段是否为0开头
int sum = 0; //sum为每一子段的数值,应在0到255之间
while (*p != '.'&&*p != '\0')
{
if (*p == ' ' || *p<'0' || *p>'9') return false;
sum = sum * 10 + *p-48; //每一子段字符串转化为整数
p++;
}
if (*p == '.') {
if ((*(p - 1) >= '0'&&*(p - 1) <= '9') && (*(p + 1) >= '0'&&*(p + 1) <= '9'))//判断"."前后是否有数字,若无,则为无效IP,如“1.1.127.”
num++; //记录“.”出现的次数,不能大于3
else
return false;
};
if ((sum > 255) || (sum > 0 && cIP[0] =='0')||num>3) return false;//若子段的值>255或为0开头的非0子段或“.”的数目>3,则为无效IP
if (*p != '\0') p++;
n = 0;
}
if (num != 3) return false;
return true;
}