Initial commit
This commit is contained in:
@@ -0,0 +1,383 @@
|
||||
#include<sys/types.h>
|
||||
#include<sys/socket.h>
|
||||
#include<arpa/inet.h>
|
||||
#include<unistd.h>
|
||||
#include<fcntl.h>
|
||||
#include<sys/epoll.h>
|
||||
#include<poll.h>
|
||||
#include<sys/timerfd.h>
|
||||
#include<map>
|
||||
|
||||
#include "Socket.h"
|
||||
#include "debug.h"
|
||||
#include "MessageHandle.h"
|
||||
#include "EpollThread.h"
|
||||
|
||||
#define TIMER_INTERVAL 5
|
||||
#define TIMER_EXPIRE 60
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//HandlerThread
|
||||
EpollHandler::HandlerThread::HandlerThread(EpollHandler* pHandler, CSema* pSema)
|
||||
: CThread(3000)
|
||||
{
|
||||
m_pHandler = pHandler;
|
||||
m_pSema = pSema;
|
||||
}
|
||||
|
||||
void EpollHandler::HandlerThread::Main()
|
||||
{
|
||||
while(!m_bExit){
|
||||
RECVBUFF* pRB = m_pHandler->GetBuff();
|
||||
if(pRB){
|
||||
// send(pRB->socket, pRB->buffer, pRB->buffsize, 0);
|
||||
TNETMESSAGE msgRequest;
|
||||
if( !m_bExit && ReadNetMessage( (unsigned char*)pRB->buffer, pRB->buffsize, &msgRequest )){
|
||||
TNETMESSAGE msgResponse;
|
||||
|
||||
struct sockaddr_in peerAddr;
|
||||
UINT peerLen = sizeof(peerAddr);
|
||||
if( getpeername(pRB->socket, (struct sockaddr *)&peerAddr, &peerLen)<0 ){
|
||||
DebugPrint("getpeername error: %d", errno);
|
||||
}
|
||||
|
||||
USHORT peerPort = ntohs(peerAddr.sin_port);
|
||||
if(msgRequest.iExtra < 0x0D00){
|
||||
memcpy(msgRequest.idDevice, &peerAddr.sin_addr, 4);
|
||||
memcpy(msgRequest.idDevice+4, &peerAddr.sin_port, 2);
|
||||
}
|
||||
else{
|
||||
memcpy(msgResponse.idDevice, msgRequest.idDevice, 6);
|
||||
}
|
||||
// if( msgRequest.eMessageType==e_versionRequest ){
|
||||
// DebugPrint( "CONNECT %s:%d type: TCP", inet_ntoa(peerAddr.sin_addr), peerPort );
|
||||
// }
|
||||
|
||||
if( !m_bExit && HandleRequest( &msgRequest, &msgResponse, peerAddr.sin_addr.s_addr, peerPort ) ){
|
||||
short nSize = DATA_BUFSIZE;
|
||||
if( !m_bExit && WriteNetMessage( (unsigned char*)pRB->buffer, nSize, &msgResponse ) ){
|
||||
if( send(pRB->socket, pRB->buffer, nSize, 0) == SOCKET_ERROR){
|
||||
DebugPrint("send() failed with error %d", errno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete pRB;
|
||||
}
|
||||
else{
|
||||
m_pSema->ActP();
|
||||
}
|
||||
}
|
||||
|
||||
DebugPrint("EpollHandlerThread exit");
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//EpollHandler
|
||||
EpollHandler::EpollHandler()
|
||||
: m_smProcess(NULL, 0), m_smBuffers(NULL, 1)
|
||||
{
|
||||
for(int i=0; i<MAX_THREAD_NUM; i++){
|
||||
m_lstThreads[i] = new HandlerThread(this, &m_smProcess);
|
||||
m_lstThreads[i]->Resume();
|
||||
}
|
||||
}
|
||||
|
||||
EpollHandler::~EpollHandler()
|
||||
{
|
||||
for(int i=0; i<MAX_THREAD_NUM; i++){
|
||||
delete m_lstThreads[i];
|
||||
m_lstThreads[i] = NULL;
|
||||
}
|
||||
|
||||
CMutexLock lockProcess( &m_smBuffers );
|
||||
while(m_lstBuff.size()){
|
||||
delete m_lstBuff.back();
|
||||
m_lstBuff.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void EpollHandler::AddBuff(RECVBUFF* pRB)
|
||||
{
|
||||
CMutexLock lockProcess( &m_smBuffers );
|
||||
m_lstBuff.push_back(pRB);
|
||||
|
||||
m_smProcess.ActV();
|
||||
}
|
||||
|
||||
RECVBUFF* EpollHandler::GetBuff()
|
||||
{
|
||||
CMutexLock lockProcess( &m_smBuffers );
|
||||
|
||||
RECVBUFF* pRB = NULL;
|
||||
if(!m_lstBuff.empty()){
|
||||
pRB = m_lstBuff.front();
|
||||
m_lstBuff.pop_front();
|
||||
}
|
||||
return pRB;
|
||||
}
|
||||
|
||||
void EpollHandler::Terminate()
|
||||
{
|
||||
//Set Thread Terminated status
|
||||
for(int i=0; i<MAX_THREAD_NUM; i++){
|
||||
m_lstThreads[i]->Terminate();
|
||||
}
|
||||
|
||||
//Release sema individully
|
||||
for(int i=0; i<MAX_THREAD_NUM; i++){
|
||||
m_smProcess.ActV();
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//EpollThread
|
||||
EpollThread::EpollThread()
|
||||
: CThread(5000)
|
||||
{
|
||||
m_pHandler = new EpollHandler();
|
||||
if(pipe(m_fdPipe)<0){
|
||||
DebugPrint("create pipe error: %d", errno);
|
||||
memset(m_fdPipe,0,sizeof(m_fdPipe));
|
||||
}
|
||||
}
|
||||
|
||||
EpollThread::~EpollThread()
|
||||
{
|
||||
if(!IsTerminated()){
|
||||
Terminate();
|
||||
}
|
||||
|
||||
if(m_pHandler){
|
||||
delete m_pHandler;
|
||||
m_pHandler = NULL;
|
||||
}
|
||||
|
||||
if(m_fdPipe[0]){
|
||||
close(m_fdPipe[0]);
|
||||
close(m_fdPipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EpollThread::SetNoBlock(int fd)
|
||||
{
|
||||
int oldSocketFlag = fcntl(fd, F_GETFL, 0);
|
||||
int newSocketFlag = oldSocketFlag | O_NONBLOCK;
|
||||
if (fcntl(fd, F_SETFL, newSocketFlag) == -1){
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EpollThread::Terminate()
|
||||
{
|
||||
CThread::Terminate();
|
||||
|
||||
if(m_fdPipe[1])
|
||||
write(m_fdPipe[1], "0", 1);
|
||||
|
||||
if(m_pHandler)
|
||||
m_pHandler->Terminate();
|
||||
}
|
||||
|
||||
void EpollThread::Main()
|
||||
{
|
||||
//创建一个监听socket
|
||||
int listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
||||
if (listenfd == -1){
|
||||
DebugPrint("create listen socket error");
|
||||
return;
|
||||
}
|
||||
|
||||
//设置重用ip地址和端口号
|
||||
int on = 1;
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char*)& on, sizeof(on));
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEPORT, (char*)& on, sizeof(on));
|
||||
|
||||
//初始化服务器地址
|
||||
struct sockaddr_in bindaddr;
|
||||
bindaddr.sin_family = AF_INET;
|
||||
bindaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
bindaddr.sin_port = htons(LISTEN_PORT);
|
||||
|
||||
if (bind(listenfd, (struct sockaddr*) & bindaddr, sizeof(bindaddr)) == -1)
|
||||
{
|
||||
close(listenfd);
|
||||
DebugPrint("bind listen socker error.");
|
||||
return;
|
||||
}
|
||||
|
||||
//启动监听
|
||||
if (listen(listenfd, SOMAXCONN) == -1){
|
||||
close(listenfd);
|
||||
DebugPrint("listen error.");
|
||||
return;
|
||||
}
|
||||
|
||||
//创建epollfd
|
||||
int epollfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epollfd == -1){
|
||||
DebugPrint("create epollfd error.");
|
||||
close(listenfd);
|
||||
return;
|
||||
}
|
||||
|
||||
epoll_event listen_fd_event;
|
||||
listen_fd_event.data.fd = listenfd;
|
||||
listen_fd_event.events = EPOLLIN;
|
||||
|
||||
//将监听sokcet绑定到epollfd上去
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &listen_fd_event) == -1){
|
||||
DebugPrint("epoll_ctl error");
|
||||
close(listenfd);
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_fdPipe[0]){
|
||||
struct epoll_event ev;
|
||||
ev.data.fd = m_fdPipe[0];
|
||||
ev.events = EPOLLIN; //水平触发方式,监听可读事件,即管道有数据可以读取了
|
||||
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, m_fdPipe[0], &ev)<0){
|
||||
DebugPrint("epoll_ctl_add pipe error: %d", errno);
|
||||
}
|
||||
}
|
||||
|
||||
int timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
|
||||
if(timerfd!=-1 ){
|
||||
struct itimerspec newValue = {};
|
||||
newValue.it_interval.tv_sec = TIMER_INTERVAL;
|
||||
newValue.it_value.tv_sec = TIMER_INTERVAL;
|
||||
if(timerfd_settime(timerfd, 0, &newValue, NULL)==-1){
|
||||
DebugPrint("settime error");
|
||||
close(timerfd);
|
||||
}
|
||||
else{
|
||||
epoll_event timer_event;
|
||||
timer_event.data.fd = timerfd;
|
||||
timer_event.events = EPOLLIN;
|
||||
|
||||
if(epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &timer_event)<0){
|
||||
DebugPrint("epoll_ctl_add timer error: %d", errno);
|
||||
close(timerfd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
map<int, int> mapFds; //tcp连接组
|
||||
int maxCount = 0;
|
||||
epoll_event epoll_events[1024];
|
||||
char dataBuff[DATA_BUFSIZE];
|
||||
while(!m_bExit){
|
||||
int n = epoll_wait(epollfd, epoll_events, 1024, -1);
|
||||
if(n < 0){
|
||||
//被信号中断
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
//出错,退出
|
||||
DebugPrint("epoll exit with error: %d", errno);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n && !m_bExit; ++i) {
|
||||
if (epoll_events[i].data.fd == m_fdPipe[0]){ //exit signal
|
||||
DebugPrint("Got epoll exit signal");
|
||||
break;
|
||||
}
|
||||
else if (epoll_events[i].data.fd == timerfd){
|
||||
// DebugPrint("epoll timer on");
|
||||
uint64_t exp=0;
|
||||
if(read(timerfd, &exp, sizeof(uint64_t))!=sizeof(uint64_t)){
|
||||
close(timerfd);
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for(auto it=mapFds.begin(); it!=mapFds.end();){
|
||||
it->second += TIMER_INTERVAL;
|
||||
|
||||
if( it->second >= TIMER_EXPIRE ){//空闲1分钟关闭
|
||||
close(it->first);
|
||||
it = mapFds.erase(it);
|
||||
// DebugPrint("close expired socket");
|
||||
}
|
||||
else{
|
||||
count++;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
if(count>maxCount){
|
||||
DebugPrint("mapFds max size: %d", count);
|
||||
maxCount = count;
|
||||
}
|
||||
}
|
||||
else if (epoll_events[i].data.fd == listenfd){
|
||||
if(epoll_events[i].events & EPOLLIN){//侦听socket,接受新连接
|
||||
struct sockaddr_in clientaddr;
|
||||
socklen_t clientaddrlen = sizeof(clientaddr);
|
||||
int clientfd = accept4(listenfd, (struct sockaddr*)&clientaddr, &clientaddrlen, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (clientfd != -1){
|
||||
epoll_event client_event;
|
||||
client_event.data.fd = clientfd;
|
||||
client_event.events = EPOLLIN | EPOLLRDHUP;// | EPOLLET;
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, clientfd, &client_event) == -1){
|
||||
DebugPrint("add client fd to epollfd error");
|
||||
close(clientfd);
|
||||
}
|
||||
// DebugPrint("add client fd %d to epollfd", clientfd);
|
||||
// mapFds.insert(clientfd, 0);
|
||||
mapFds[clientfd] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (epoll_events[i].events & EPOLLRDHUP ) {
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) == -1){
|
||||
// DebugPrint("EPOLL_CTL_DEL clientfd %d by event %d", epoll_events[i].data.fd, epoll_events[i].events);
|
||||
// }
|
||||
// else{
|
||||
DebugPrint("EPOLL_CTL_DEL clientfd %d by event %d error", epoll_events[i].data.fd, epoll_events[i].events);
|
||||
}
|
||||
|
||||
close(epoll_events[i].data.fd);
|
||||
|
||||
mapFds.erase(mapFds.find(epoll_events[i].data.fd));
|
||||
}
|
||||
else if (epoll_events[i].events & EPOLLIN){ //事件可读
|
||||
// DebugPrint("client fd: %d recv data.", epoll_events[i].data.fd);
|
||||
|
||||
int m = recv(epoll_events[i].data.fd, dataBuff, DATA_BUFSIZE, 0);
|
||||
|
||||
// DebugPrint("read data size %d", m);
|
||||
|
||||
if( m>0 && ValidNetMessage((UCHAR*)dataBuff, m) ){
|
||||
RECVBUFF* pRB = new RECVBUFF;
|
||||
memcpy(pRB->buffer, dataBuff, m);
|
||||
pRB->socket = epoll_events[i].data.fd;
|
||||
pRB->buffsize = m;
|
||||
|
||||
m_pHandler->AddBuff(pRB);
|
||||
}
|
||||
else if (m <= 0 && errno != EWOULDBLOCK && errno != EINTR){ //对端关闭了连接,从epollfd上移除clientfd
|
||||
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, epoll_events[i].data.fd, NULL) == -1){
|
||||
// DebugPrint("EPOLL_CTL_DEL clientfd %d normally", epoll_events[i].data.fd);
|
||||
// }
|
||||
// else{
|
||||
DebugPrint("EPOLL_CTL_DEL clientfd %d by EPOLLIN error", epoll_events[i].data.fd);
|
||||
}
|
||||
|
||||
close(epoll_events[i].data.fd);
|
||||
mapFds.erase(mapFds.find(epoll_events[i].data.fd));
|
||||
}
|
||||
|
||||
mapFds.find(epoll_events[i].data.fd)->second = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(epollfd);
|
||||
|
||||
DebugPrint("EPOLL main exit");
|
||||
}
|
||||
Reference in New Issue
Block a user