#ifndef H_NETDEF_H
#define H_NETDEF_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#ifdef WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#else
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>
#include <assert.h>
#include <netinet/tcp.h>
#include <semaphore.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <sys/epoll.h>
#include <unordered_map>
#include <unordered_set>
#define EWOULDBLOCK EAGAIN
#define SOCKET_ERROR (-1)
#define closesocket close
#define INVALID_SOCKET (SOCKET)(~0)
typedef int SOCKET;
typedef int EPOLL;
#endif
// TCP
#define DEF_READ_BUF_TCP (1460)
struct S_TcpDataBuf
{
char m_szBuf[DEF_READ_BUF_TCP];
int m_iBufLen;
SOCKET m_oSocket;
};
struct S_TcpConnect
{
SOCKET m_oSocket;
struct sockaddr_in m_oAddress;
int64_t m_i64ConnectTime;
S_TcpConnect()
{
m_oSocket = -1;
memset((void*)&m_oAddress, 0, sizeof(struct sockaddr_in) );
m_i64ConnectTime = 0;
}
};
class ITcpNotice
{
public:
virtual int OnConnect( SOCKET aoSocket, struct sockaddr_in& loAddr) = 0;
virtual int OnClose( SOCKET aoSocket) = 0;
virtual int OnRecv( SOCKET aoSocket, char* apBuf, int aiLen ) = 0;
};
#define DEF_READ_BUF_UDP (1472)
#endif // H_NETDEF_H
/*
A:Snight
QQ:51171107
*/
#ifndef H_DEF_EPOLLSVR_H
#define H_DEF_EPOLLSVR_H
#include <string.h>
#include <queue>
#include "CCrt.h"
#include "NetDef.h"
#include "SocketHelper.h"
class CEpollTcpSvr
{
public:
CEpollTcpSvr( void );
~CEpollTcpSvr( void );
public:
bool StartSvr( int aiPort , int aiTaskThreadCnt, int aiCatchSize, int aiMaxSocketCnt = 10000);
bool SendData(SOCKET aoSocket, char* apBuf, int aiLen);
private:
void UpdateEvents( EPOLL aoEpoll, SOCKET aoSocket, int aoEvent, int aoOpt );
bool OnEpollET(struct epoll_event* aoEvents, int aiNum, EPOLL aoEpoll, SOCKET aoListenFd);
void OnConnect(SOCKET aoSocket, struct sockaddr_in& aoAddr);
void OnCutdown(SOCKET apConnect);
static void* _WorkThread(void * apThis);
void WorkThread(void);
static void* _CheckThread(void * apThis);
void CheckThread(void);
static void* _TaskThread(void * apThis);
void TaskThread(void);
S_TcpDataBuf* GetDataBuf( void );
void BackDataBuf(S_TcpDataBuf* apBuf );
S_TcpConnect* GetConnect(void);
void BackConnect(S_TcpConnect* apBuf);
private:
bool m_bIsInit;
int m_iSockaddrinLen;
int m_iMaxSocketCnt;
SOCKET m_oLsnSocket;
EPOLL m_oEpollFD;
pthread_t m_oWorkThread;
pthread_t m_oCheckThread;
pthread_t* m_pTaskThread;
int m_iTaskThreadCnt;
ITcpNotice* m_pTcpNotice;
int m_iTotalCCnt;
int64_t m_i64TotalRecvPackageCnt;
double m_dTotalRecvKByte;
int64_t m_i64TotalSendPackageCnt;
double m_dTotalSendKByte;
// 缓存buf
std::queue<S_TcpDataBuf*> m_oDataCatchBufQueue;
std::recursive_mutex m_oDataCatchBufQueueLock;
int m_iMaxCacheSize;
// 任务buf
std::queue<S_TcpDataBuf*> m_oDataTaskBufQueue;
std::recursive_mutex m_oDataTaskBufQueueLock;
// 连接
std::unordered_map< SOCKET, S_TcpConnect* > m_oConectMap;
std::recursive_mutex m_oConectMapLock;
// 缓存buf
std::queue<S_TcpConnect*> m_oConnectCatchQueue;
std::recursive_mutex m_oConnectCatchQueueLock;
};
#endif //H_DEF_EPOLLSVR_H
#include "EpollTcpSvr.h"
#define MAX_EVENT_NUM (6666)
CEpollTcpSvr::CEpollTcpSvr()
{
m_pTcpNotice = NULL;
m_iTotalCCnt = 0;
m_i64TotalRecvPackageCnt = 0;
m_dTotalRecvKByte = 0;
m_i64TotalSendPackageCnt = 0;
m_dTotalSendKByte = 0;
m_bIsInit = false;
m_iMaxCacheSize = 1000;
m_iSockaddrinLen = sizeof(struct sockaddr_in);
}
CEpollTcpSvr::~CEpollTcpSvr()
{
}
void CEpollTcpSvr::OnConnect(SOCKET aoSocket, struct sockaddr_in& aoAddr)
{
if (m_pTcpNotice) m_pTcpNotice->OnConnect(aoSocket, aoAddr);
}
void CEpollTcpSvr::OnCutdown(SOCKET aoSocket)
{
if (m_pTcpNotice) m_pTcpNotice->OnClose(aoSocket);
m_oConectMapLock.lock();
std::unordered_map< SOCKET, S_TcpConnect* >::iterator liIter = m_oConectMap.find(aoSocket);
if (liIter != m_oConectMap.end())
{
BackConnect(liIter->second);
m_oConectMap.erase(aoSocket);
}
else
{
printf("INFO: UnKnowConnect");
}
m_iTotalCCnt = m_oConectMap.size();
m_oConectMapLock.unlock();
printf("[INFO] OnCutdown SOCKET:%d Total:%d\n", aoSocket, m_iTotalCCnt);
epoll_ctl(m_oEpollFD, EPOLL_CTL_DEL, aoSocket, 0); // 为什么没有看到有人删除他
closesocket(aoSocket);
}
void CEpollTcpSvr::UpdateEvents( EPOLL aoEpoll, SOCKET aoSocket, int aoEvent, int aoOpt )
{
struct epoll_event loEvent;
memset( &loEvent, 0, sizeof( loEvent ) );
loEvent.events = aoEvent;
loEvent.data.fd = aoSocket;
epoll_ctl(aoEpoll, aoOpt, aoSocket, &loEvent);
}
bool CEpollTcpSvr::StartSvr(int aiPort, int aiTaskThreadCnt, int aiCatchSize, int aiMaxSocketCnt)
{
if (m_bIsInit) return true;
m_iMaxSocketCnt = aiMaxSocketCnt;
m_iTaskThreadCnt = aiTaskThreadCnt;
m_iMaxCacheSize = aiCatchSize;
m_oLsnSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
CSocketHelper::SetNonBlock( m_oLsnSocket );
CSocketHelper::SetReuseAddr(m_oLsnSocket);
CSocketHelper::SetNodelay( m_oLsnSocket );
struct sockaddr_in loAddr;
memset(&loAddr, 0, m_iSockaddrinLen);
loAddr.sin_family = AF_INET;
loAddr.sin_port = htons(aiPort);
loAddr.sin_addr.s_addr = INADDR_ANY;
int ret = ::bind(m_oLsnSocket, (struct sockaddr*)&loAddr, m_iSockaddrinLen);
if (SOCKET_ERROR == ret)
{
closesocket(m_oLsnSocket);
return false;
}
printf("[INFO] bind/n");
ret = ::listen( m_oLsnSocket, 20 );
if (SOCKET_ERROR == ret)
{
closesocket(m_oLsnSocket);
return false;
}
printf("[INFO] listen/n");
m_oEpollFD = epoll_create(5);
//UpdateEvents(m_oEpollFD, m_oLsnSocket, EPOLLIN , EPOLL_CTL_ADD);
UpdateEvents(m_oEpollFD, m_oLsnSocket, EPOLLIN | EPOLLET| EPOLLERR, EPOLL_CTL_ADD);
printf("[INFO] UpdateEvents/n");
int err = pthread_create(&m_oWorkThread, NULL, _WorkThread, this); //创建线程
if (err != 0)
{
printf("[ERROR]create m_oWorkThread error: %s/n", strerror(err));
return false;
}
err = pthread_create(&m_oCheckThread, NULL, _CheckThread, this); //创建线程
if (err != 0)
{
printf("[ERROR]create m_oCheckThread error: %s/n", strerror(err));
return false;
}
if (m_iTaskThreadCnt <= 0) m_iTaskThreadCnt = 1;
m_pTaskThread = new pthread_t[m_iTaskThreadCnt];
for ( int i = 0; i < m_iTaskThreadCnt; ++i )
{
pthread_create(&m_pTaskThread[i], NULL, _TaskThread, this);
}
printf("[INFO] Start Succeed Epoll:%d Socket:%d LsnPort:%d\n", m_oEpollFD, m_oLsnSocket, aiPort);
return true;
}
void* CEpollTcpSvr::_WorkThread(void * apThis)
{
printf("[INFO] _WorkThread\n");
if (apThis)
{
CEpollTcpSvr* lpThis = (CEpollTcpSvr*)apThis;
lpThis->WorkThread();
}
return NULL;
}
void CEpollTcpSvr::WorkThread(void)
{
struct epoll_event loEvents[MAX_EVENT_NUM];
while (true)
{
int liRet = epoll_wait(m_oEpollFD, loEvents, MAX_EVENT_NUM, -1);
if (liRet == -1)
{
if (errno == EINTR)
{
printf("[INFO] Epoll wait EINTR Continue\n");
continue;
}
else
{
printf("[INFO] Epoll wait Error\n");
closesocket(m_oEpollFD);
exit(EXIT_FAILURE);
}
}
OnEpollET(loEvents, liRet, m_oEpollFD, m_oLsnSocket);
}
closesocket(m_oEpollFD);
}
bool CEpollTcpSvr::OnEpollET(struct epoll_event* aoEvents, int aiNum, EPOLL aoEpoll, SOCKET aoListenFd)
{
char lszBuf[DEF_READ_BUF_TCP + 1];
for (int i = 0; i < aiNum; ++i)
{
int loClientFd = aoEvents[i].data.fd;
if (loClientFd == aoListenFd)
{
do
{
S_TcpConnect* lpConnect = GetConnect();
socklen_t loAddrLen = m_iSockaddrinLen;
lpConnect->m_oSocket = accept(aoListenFd, (struct sockaddr*)&lpConnect->m_oAddress, &loAddrLen);
if (-1 == lpConnect->m_oSocket)
{
if ( errno == EAGAIN)
{
BackConnect(lpConnect);
break;
}
else if (errno == EINTR)
{
// 非阻塞状态应该不会出现的.
printf("[INFO] Epoll accept EINTR\n");
BackConnect(lpConnect);
continue;
}
printf("[INFO] Epoll accept false\n");
return false;
}
// 限制连接数
if (m_iTotalCCnt > m_iMaxSocketCnt)
{
closesocket(lpConnect->m_oSocket);
BackConnect(lpConnect);
break;
}
m_oConectMapLock.lock();
m_oConectMap.insert(std::make_pair(lpConnect->m_oSocket, lpConnect));
m_iTotalCCnt = m_oConectMap.size();
m_oConectMapLock.unlock();
CSocketHelper::SetNonBlock(lpConnect->m_oSocket);
CSocketHelper::SetNodelay(lpConnect->m_oSocket);
UpdateEvents(m_oEpollFD, lpConnect->m_oSocket, EPOLLIN|EPOLLET|EPOLLRDHUP|EPOLLERR, EPOLL_CTL_ADD);
OnConnect(lpConnect->m_oSocket, lpConnect->m_oAddress);
} while (true);
}
else
{
if (( aoEvents[i].events & EPOLLERR) ||
( aoEvents[i].events & EPOLLHUP) ||
( aoEvents[i].events & EPOLLRDHUP ) )
{
OnCutdown(aoEvents[i].data.fd);
continue;
}
do
{
S_TcpDataBuf* lpBuf = GetDataBuf();
lpBuf->m_iBufLen = ::read(loClientFd, lpBuf->m_szBuf, DEF_READ_BUF_TCP);
if ( lpBuf->m_iBufLen > 0 )
{
m_i64TotalRecvPackageCnt += 1;
double ldTem = lpBuf->m_iBufLen;
m_dTotalRecvKByte += ldTem / 1024;
lpBuf->m_oSocket = loClientFd;
m_oDataTaskBufQueueLock.lock();
m_oDataTaskBufQueue.push(lpBuf);
m_oDataTaskBufQueueLock.unlock();
}
else if ( lpBuf->m_iBufLen == -1 )
{
if ( ( errno == EAGAIN ) )
{
BackDataBuf(lpBuf);
break;
}
else
{
BackDataBuf(lpBuf);
OnCutdown(loClientFd);
break;
}
}
else
{
BackDataBuf(lpBuf);
OnCutdown(loClientFd);
break;
}
} while (true);
}
}
return true;
}
void* CEpollTcpSvr::_CheckThread(void * apThis)
{
printf("[INFO] _CheckThread/n");
if (apThis)
{
CEpollTcpSvr* lpThis = (CEpollTcpSvr*)apThis;
lpThis->CheckThread();
}
return NULL;
}
void CEpollTcpSvr::CheckThread(void)
{
int64_t li64OldRecvPackageCnt = 0;
double ldwOldRecvKb = 0;
int64_t li64OldSendPackageCnt = 0;
double ldwOldSendKb = 0;
while (true)
{
int liSize1 = m_oDataCatchBufQueue.size();
int liSize2 = m_oDataTaskBufQueue.size();
printf("[INFO] CON:%d [R:(%ld %.2lf KB)(%ld %.2lfKB)][S:(%ld %.2lf KB)(%ld %.2lfKB)][BC:%d, BT:%d][CC:%d]\n",
m_iTotalCCnt, m_i64TotalRecvPackageCnt,
m_dTotalRecvKByte,
(m_i64TotalRecvPackageCnt - li64OldRecvPackageCnt),
(m_dTotalRecvKByte - ldwOldRecvKb),
m_i64TotalSendPackageCnt, m_dTotalSendKByte,
(m_i64TotalSendPackageCnt - li64OldSendPackageCnt),
(m_dTotalSendKByte - ldwOldSendKb),
m_oDataCatchBufQueue.size(), m_oDataTaskBufQueue.size(),
m_oConnectCatchQueue.size());
li64OldRecvPackageCnt = m_i64TotalRecvPackageCnt;
ldwOldRecvKb = m_dTotalRecvKByte;
li64OldSendPackageCnt = m_i64TotalSendPackageCnt;
ldwOldSendKb = m_dTotalSendKByte;
int a;
a = 10;
CrtSecSleep(1);
}
}
void* CEpollTcpSvr::_TaskThread(void * apThis)
{
if (apThis)
{
CEpollTcpSvr* lpThis = (CEpollTcpSvr*)apThis;
lpThis->TaskThread();
}
return NULL;
}
void CEpollTcpSvr::TaskThread(void)
{
while (true)
{
S_TcpDataBuf* lpBuf = NULL;
{
S_AutoLock lo(&m_oDataTaskBufQueueLock);
if (m_oDataTaskBufQueue.size() > 0)
{
lpBuf = m_oDataTaskBufQueue.front();
m_oDataTaskBufQueue.pop();
}
}
if (lpBuf)
{
if (m_pTcpNotice)
{
m_pTcpNotice->OnRecv(lpBuf->m_oSocket, lpBuf->m_szBuf, lpBuf->m_iBufLen);
}
//SendData(lpBuf->m_oSocket, lpBuf->m_szBuf, lpBuf->m_iBufLen);
BackDataBuf(lpBuf);
continue;
}
CrtMiscSleep(100);
}
}
bool CEpollTcpSvr::SendData(SOCKET aoSocket, char* apBuf, int aiLen)
{
int liPerSend = 0;
int liNeedSend = aiLen;
int liRealSend = 0;
while (true)
{
liPerSend = write(aoSocket, apBuf, liNeedSend);
if ( liPerSend == -1 )
{
if ( errno == EAGAIN )
{
return true;
}
closesocket(aoSocket);
return false;
}
else if (liPerSend == 0)
{
printf("[INFO] SOCKET CUTDOWN %d\n", liPerSend);
closesocket(aoSocket);
return false;
}
liRealSend += liPerSend;
if (liRealSend < aiLen)
{
liNeedSend -= liPerSend;
apBuf += liPerSend;
}
else if (liRealSend == aiLen)
break;
}
m_i64TotalSendPackageCnt++;
double ldTemp = liRealSend;
m_dTotalSendKByte += (ldTemp/1024);
return true;
}
S_TcpDataBuf* CEpollTcpSvr::GetDataBuf(void)
{
m_oDataCatchBufQueueLock.lock();
if (m_oDataCatchBufQueue.size() > 0)
{
S_TcpDataBuf* lpBuf = m_oDataCatchBufQueue.front();
m_oDataCatchBufQueue.pop();
m_oDataCatchBufQueueLock.unlock();
return lpBuf;
}
else
{
m_oDataCatchBufQueueLock.unlock();
return (new S_TcpDataBuf);
}
}
void CEpollTcpSvr::BackDataBuf(S_TcpDataBuf* apBuf)
{
m_oDataCatchBufQueueLock.lock();
if (m_oDataCatchBufQueue.size() < m_iMaxCacheSize)
{
memset(apBuf, 0, sizeof(char)* DEF_READ_BUF_TCP);
m_oDataCatchBufQueue.push(apBuf);
m_oDataCatchBufQueueLock.unlock();
}
else
{
m_oDataCatchBufQueueLock.unlock();
delete apBuf;
}
}
S_TcpConnect* CEpollTcpSvr::GetConnect(void)
{
m_oConnectCatchQueueLock.lock();
if (m_oConnectCatchQueue.size() > 0)
{
S_TcpConnect* lpConnect = m_oConnectCatchQueue.front();
m_oConnectCatchQueue.pop();
m_oConnectCatchQueueLock.unlock();
return lpConnect;
}
else
{
m_oConnectCatchQueueLock.unlock();
return (new S_TcpConnect);
}
}
void CEpollTcpSvr::BackConnect(S_TcpConnect* apConnect)
{
m_oConnectCatchQueueLock.lock();
if (m_oConnectCatchQueue.size() < m_iMaxCacheSize)
{
apConnect->m_oSocket = -1;
memset(&apConnect->m_oAddress, 0, m_iSockaddrinLen);
apConnect->m_i64ConnectTime = 0;
m_oConnectCatchQueue.push(apConnect);
m_oConnectCatchQueueLock.unlock();
//printf("INFO:BACK %d\n", m_oConnectCatchQueue.size());
}
else
{
//printf("INFO:delete %d\n", m_oConnectCatchQueue.size());
m_oConnectCatchQueueLock.unlock();
delete apConnect;
}
}