420 lines
9.1 KiB
C++
420 lines
9.1 KiB
C++
#include "CYTCPServer.h"
|
||
#include <stdio.h>
|
||
#include <thread>
|
||
#include <algorithm>
|
||
#include <cmath>
|
||
#include <cstring>
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#include <WS2tcpip.h>
|
||
#else
|
||
#include <sys/types.h>
|
||
#include <sys/socket.h>
|
||
#include <unistd.h>
|
||
#include <netinet/in.h>
|
||
#include <arpa/inet.h>
|
||
#include <sys/select.h>
|
||
#include <sys/time.h>
|
||
#include <functional>
|
||
#include <linux/tcp.h>
|
||
#endif // _WIN32
|
||
|
||
CYTCPServer::CYTCPServer()
|
||
: m_eWorkStats(WORK_INIT)
|
||
, m_nSocket(INVALID_SOCKET)
|
||
, m_bWork(false)
|
||
, m_fRecv(nullptr)
|
||
, m_fEvent(nullptr)
|
||
, m_bCreateRecv(false)
|
||
, m_bOffNagle(false)
|
||
{
|
||
m_vTCPClient.clear();
|
||
}
|
||
|
||
CYTCPServer::~CYTCPServer()
|
||
{
|
||
Close();
|
||
}
|
||
|
||
///<2F><>ʼ<EFBFBD><CABC>socket
|
||
bool CYTCPServer::Init(const int port, bool bOffNagle)
|
||
{
|
||
bool bRet = false;
|
||
#ifdef _WIN32
|
||
WORD ver = MAKEWORD(2, 2);
|
||
WSADATA data;
|
||
WSAStartup(ver, &data);
|
||
#endif // _WIN32
|
||
|
||
m_nSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||
if (m_nSocket != INVALID_SOCKET)
|
||
{
|
||
bRet = true;
|
||
sockaddr_in sSockAddr;
|
||
sSockAddr.sin_family = AF_INET;
|
||
sSockAddr.sin_port = htons(port);//host to net unsigned short
|
||
#ifdef _WIN32
|
||
sSockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
|
||
#else
|
||
sSockAddr.sin_addr.s_addr = INADDR_ANY;
|
||
memset(sSockAddr.sin_zero, 0, 8);
|
||
|
||
int opt = SO_REUSEADDR;
|
||
int len = sizeof(opt);
|
||
setsockopt(m_nSocket, SOL_SOCKET, SO_REUSEADDR, &opt, len);
|
||
|
||
if(bOffNagle)
|
||
{
|
||
int on = 1; //<2F>Ƿ<EFBFBD><C7B7>nagle<6C>㷨<EFBFBD><E3B7A8> //1 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><CDB5><EFBFBD>tcp<63><70> 0<><30><EFBFBD><EFBFBD>ӳٷ<D3B3><D9B7><EFBFBD>tcp<63><70>
|
||
setsockopt(m_nSocket, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on));
|
||
}
|
||
|
||
#endif // _WIN32
|
||
|
||
int nRet = bind(m_nSocket, (struct sockaddr*)&sSockAddr, sizeof(sockaddr_in));
|
||
if (SOCKET_ERROR != nRet)
|
||
{
|
||
nRet = listen(m_nSocket, 50);
|
||
if (SOCKET_ERROR == nRet)
|
||
{
|
||
bRet = false;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
printf("bind %d failed \n", port);
|
||
bRet = false;
|
||
}
|
||
|
||
if (!bRet)
|
||
{
|
||
#ifdef _WIN32
|
||
closesocket(m_nSocket);
|
||
#else
|
||
close(m_nSocket);
|
||
#endif
|
||
m_nSocket = INVALID_SOCKET;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
bRet = false;
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
bool CYTCPServer::Start(FunTCPServerRecv fRecv, bool bRecvSelfProtocol)
|
||
{
|
||
//1<><31><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
||
m_bWork = true;
|
||
//2<><32><EFBFBD><EFBFBD>ֵ<EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>
|
||
m_fRecv = fRecv;
|
||
|
||
//3<><33>ע<EFBFBD><D7A2>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3><CCA3><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>Ϊnull <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>RecvData<74>ӿ<EFBFBD>
|
||
if (!m_bCreateRecv)
|
||
{
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߳̽<DFB3><CCBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>
|
||
std::thread tLinkThread(std::bind(&CYTCPServer::_OnMonitorLink, this));
|
||
tLinkThread.detach();
|
||
//<2F>״ν<D7B4><CEBD><EFBFBD>ֱ<EFBFBD>ӽ<EFBFBD><D3BD><EFBFBD>runing ״̬
|
||
m_eWorkStats = WORK_RUNING;
|
||
m_bCreateRecv = true;
|
||
|
||
///<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Task
|
||
std::lock_guard<std::mutex> oLck(m_mVectorTask);
|
||
for (int i = (int)floor(MAX_CLIENT_NUM / FD_SETSIZE); i >= 0; i--)
|
||
{
|
||
CYServerTask* pServerTask = new CYServerTask();
|
||
m_vServerTask.push_back(pServerTask);
|
||
pServerTask->StartTask(fRecv, bRecvSelfProtocol);
|
||
|
||
// 设置异常处理回调,指向CYTCPServer的_Exception方法
|
||
pServerTask->SetExceptionCallback([this](const TCPClient* pClient) {
|
||
this->_Exception(pClient);
|
||
});
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD>źŽ<C5BA><C5BD>п<EFBFBD>ʼ
|
||
while (WORK_RUNING != m_eWorkStats)
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mutexRecv);
|
||
m_cvRecv.notify_one();
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void CYTCPServer::SetEventCallback(FunTCPServerEvent fEvent)
|
||
{
|
||
m_fEvent = fEvent;
|
||
}
|
||
|
||
bool CYTCPServer::Stop()
|
||
{
|
||
m_bWork = false;
|
||
///<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˿<EFBFBD>ʼ<EFBFBD>ŵȴ<C5B5><C8B4><EFBFBD><EFBFBD><EFBFBD>
|
||
if(m_bCreateRecv)
|
||
{
|
||
while (WORK_WAITSINGAL != m_eWorkStats)
|
||
{
|
||
std::chrono::milliseconds milTime(1);
|
||
std::this_thread::sleep_for(milTime);
|
||
}
|
||
m_fRecv = nullptr;
|
||
|
||
///<2F>رշ<D8B1><D5B7><EFBFBD><EFBFBD>Task
|
||
std::lock_guard<std::mutex> oLck(m_mVectorTask);
|
||
std::vector<CYServerTask*>::iterator iter = m_vServerTask.begin();
|
||
while(iter != m_vServerTask.end())
|
||
{
|
||
(*iter)->StopTask();
|
||
iter = m_vServerTask.erase(iter);
|
||
}
|
||
}
|
||
m_bCreateRecv = false;
|
||
return true;
|
||
}
|
||
|
||
///<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ
|
||
bool CYTCPServer::SendData(const TCPClient* pClient, const char* nBuf, const int nLen)
|
||
{
|
||
if (nullptr == pClient || pClient->m_nFD == INVALID_SOCKET)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
std::lock_guard<std::mutex> mSocketLock(m_mSocketMutex);
|
||
|
||
bool bRet = false;
|
||
std::vector<TCPClient*> vTCPClient;
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mVectorSocket);
|
||
vTCPClient = m_vTCPClient;
|
||
}
|
||
|
||
for (int i = (int)vTCPClient.size() - 1; i >= 0; i--)
|
||
{
|
||
if (pClient->m_nFD == vTCPClient[i]->m_nFD)
|
||
{
|
||
#if 0
|
||
int* intBuf = (int *)nBuf;
|
||
printf("send : %x len : %d Alleln : %d\n", *(intBuf + 2), *(intBuf + 4), nLen);
|
||
#endif
|
||
int nSendLen = 0;
|
||
while (nSendLen < nLen)
|
||
{
|
||
int len = send(pClient->m_nFD, nBuf + nSendLen, nLen - nSendLen, 0);
|
||
if (len <= 0)
|
||
{
|
||
bRet = false;
|
||
break;
|
||
}
|
||
nSendLen += len;
|
||
}
|
||
|
||
if (nSendLen == nLen)
|
||
{
|
||
bRet = true;
|
||
}
|
||
}
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
///<2F><><EFBFBD><EFBFBD><CDB8><EFBFBD><EFBFBD>пͻ<D0BF><CDBB><EFBFBD>
|
||
bool CYTCPServer::SendAllData(const char* nBuf, const int nLen)
|
||
{
|
||
bool bRet = false;
|
||
std::vector<TCPClient*> vTCPClient;
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mVectorSocket);
|
||
vTCPClient = m_vTCPClient;
|
||
}
|
||
|
||
for (int i = (int)vTCPClient.size() - 1; i >= 0; i--)
|
||
{
|
||
bRet = SendData(vTCPClient[i], nBuf, nLen);
|
||
}
|
||
return bRet;
|
||
}
|
||
|
||
///<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
bool CYTCPServer::RecvData(unsigned char** ppData, unsigned int* nLen)
|
||
{
|
||
bool bRet = true;
|
||
|
||
|
||
return bRet;
|
||
}
|
||
|
||
bool CYTCPServer::Close()
|
||
{
|
||
if (INVALID_SOCKET != m_nSocket)
|
||
{
|
||
if (WORK_RUNING == m_eWorkStats)
|
||
{
|
||
Stop();
|
||
}
|
||
|
||
#ifdef _WIN32
|
||
closesocket(m_nSocket);
|
||
WSACleanup();
|
||
#else
|
||
close(m_nSocket);
|
||
#endif
|
||
m_nSocket = INVALID_SOCKET;
|
||
|
||
m_eWorkStats = WORK_CLOSE;
|
||
|
||
while (m_eWorkStats != WORK_EXIT)
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mutexRecv);
|
||
m_cvRecv.notify_one();
|
||
|
||
std::chrono::milliseconds milTime(1);
|
||
std::this_thread::sleep_for(milTime);
|
||
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
void CYTCPServer::_AddClient(const SOCKET nSocket, const sockaddr_in sClientAddr)
|
||
{
|
||
printf("index : %d welcome [%d]: %s\n", (int)m_vTCPClient.size(), (int)nSocket, inet_ntoa(sClientAddr.sin_addr));
|
||
TCPClient* pTCPClient = new TCPClient;
|
||
pTCPClient->m_nFD = (int)nSocket;
|
||
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mVectorSocket);
|
||
m_vTCPClient.push_back(pTCPClient);
|
||
}
|
||
{
|
||
std::lock_guard<std::mutex> taskLock(m_mVectorTask);
|
||
std::vector<CYServerTask*>::iterator iterMin = m_vServerTask.begin();
|
||
std::vector<CYServerTask*>::iterator iter = m_vServerTask.begin();
|
||
while (iter != m_vServerTask.end())
|
||
{
|
||
iterMin = (*iterMin)->GetClientNum() <= (*iter)->GetClientNum() ? iterMin : iter;
|
||
iter++;
|
||
}
|
||
|
||
if (iterMin != m_vServerTask.end())
|
||
{
|
||
pTCPClient->m_Task = (*iterMin);
|
||
(*iterMin)->AddClient(pTCPClient);
|
||
}
|
||
}
|
||
|
||
// 触发客户端连接事件
|
||
if (m_fEvent)
|
||
{
|
||
m_fEvent(pTCPClient, TCP_EVENT_CLIENT_CONNECTED);
|
||
}
|
||
}
|
||
|
||
void CYTCPServer::_CloseClient(const TCPClient* pClient)
|
||
{
|
||
std::unique_lock<std::mutex> lock(m_mVectorSocket);
|
||
std::vector<TCPClient*>::iterator iter = m_vTCPClient.begin();
|
||
while(iter != m_vTCPClient.end())
|
||
{
|
||
if(*iter == pClient)
|
||
{
|
||
printf("client exit [%d]\n", (int)pClient->m_nFD);
|
||
|
||
// 触发客户端断开连接事件
|
||
if (m_fEvent)
|
||
{
|
||
m_fEvent(pClient, TCP_EVENT_CLIENT_DISCONNECTED);
|
||
}
|
||
|
||
delete pClient;
|
||
m_vTCPClient.erase(iter);
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
iter++;
|
||
}
|
||
}
|
||
}
|
||
|
||
void CYTCPServer::_OnMonitorLink()
|
||
{
|
||
//select
|
||
fd_set fdRead;
|
||
fd_set fdExp;
|
||
|
||
while (true)
|
||
{
|
||
if (!m_bWork)
|
||
{
|
||
m_eWorkStats = WORK_WAITSINGAL;
|
||
std::unique_lock<std::mutex> lock(m_mutexRecv);
|
||
m_cvRecv.wait(lock);
|
||
if (WORK_CLOSE == m_eWorkStats)
|
||
{
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
m_eWorkStats = WORK_RUNING;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
FD_ZERO(&fdRead);
|
||
FD_ZERO(&fdExp);
|
||
|
||
FD_SET(m_nSocket, &fdRead);
|
||
FD_SET(m_nSocket, &fdExp);
|
||
|
||
struct timeval sWaitTime = {0, 1000};
|
||
int nCount = select((int)m_nSocket + 1, &fdRead, nullptr, &fdExp, &sWaitTime);
|
||
|
||
if (nCount <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (FD_ISSET(m_nSocket, &fdRead))
|
||
{
|
||
FD_CLR(m_nSocket, &fdRead);
|
||
sockaddr_in sClientAddr;
|
||
int nAddrLen = sizeof(sockaddr_in);
|
||
SOCKET nSocket = accept(m_nSocket, (sockaddr*)&sClientAddr, (socklen_t *)&nAddrLen);
|
||
|
||
if (INVALID_SOCKET != nSocket)
|
||
{
|
||
_AddClient(nSocket, sClientAddr);
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
m_eWorkStats = WORK_EXIT;
|
||
}
|
||
|
||
/// <20><><EFBFBD><EFBFBD><EFBFBD>쳣
|
||
void CYTCPServer::_Exception(const TCPClient* pClient)
|
||
{
|
||
// 触发客户端异常事件
|
||
if (m_fEvent)
|
||
{
|
||
m_fEvent(pClient, TCP_EVENT_CLIENT_EXCEPTION);
|
||
}
|
||
|
||
CYServerTask* p = (CYServerTask*)(pClient->m_Task);
|
||
p->DelClient(pClient);
|
||
_CloseClient(pClient);
|
||
}
|
||
|
||
bool VrCreatYTCPServer(IYTCPServer** ppIYTCPServer)
|
||
{
|
||
CYTCPServer* pYTCPServer = new CYTCPServer();
|
||
*ppIYTCPServer = pYTCPServer;
|
||
return true;
|
||
} |