Files
Client/Server/RylServerProject/BaseLibrary/Network/Iocp/IOCPNet.cpp
LGram16 dd97ddec92 Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code:
- Client: Game client source (moved to Client/Client/)
- Server: Game server source
- GameTools: Development tools
- CryptoSource: Encryption utilities
- database: Database scripts
- Script: Game scripts
- rylCoder_16.02.2008_src: Legacy coder tools
- GMFont, Game: Additional resources

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 20:17:20 +09:00

354 lines
8.1 KiB
C++

#include "stdafx.h"
#include "IOCPNet.h"
#include "IOWorker.h"
#include "CompletionHandler.h"
#include "../../Thread/ThreadMgr.h"
#include "../../Stream/Buffer/BufferFactory.h"
#include "../Session/Session.h"
#include "../Session/SessionMgr.h"
#include "../Listener/Listener.h"
#include "../Dispatch/Dispatch.h"
#include "../Winsock/SocketFactory.h"
#include "../../Utility/Resource/EnsureCleanup.h"
#include "../../Utility/Debug/DebugUtils.h"
#include "../../Log/ServerLog.h"
#include <mmsystem.h>
enum IOCPInternalFlag
{
INITIALIZED_IOCP = (1 << 0),
DESTROYED_IOCP = (1 << 1)
};
unsigned long GetOptimalThreadNum()
{
unsigned long dwThreadCount;
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
dwThreadCount = systemInfo.dwNumberOfProcessors * 2;
return dwThreadCount;
}
CIOCPNet::CIOCPNet()
: m_dwFlags(0),
m_lpSocketHandler(new (std::nothrow) CCompletionHandler),
m_lpThreadMgr(new (std::nothrow) CThreadMgr),
m_lpSessionMgr(new (std::nothrow) CSessionMgr)
{
WSADATA wsaData;
WSAStartup(0x0202, &wsaData);
}
CIOCPNet::~CIOCPNet()
{
Destroy();
WSACleanup();
}
// Desc : 초기화 및 스레드 생성.
bool CIOCPNet::Initialize()
{
{
SessionLock::Syncronize sync(m_IOCPLock);
// 초기화는 한번만 할 수 있음.
if(INITIALIZED_IOCP & m_dwFlags)
{
return false;
}
m_dwFlags |= INITIALIZED_IOCP;
}
if(0 == m_lpSocketHandler ||
0 == m_lpThreadMgr ||
0 == m_lpSessionMgr ||
!m_lpSocketHandler->Initialize())
{
return false;
}
// IOCP 스레드 생성.
unsigned long dwThreadNum = GetOptimalThreadNum();
while(0 != dwThreadNum--)
{
if(!m_lpThreadMgr->RegisterAndRun(
new (std::nothrow) CIOWorker(*m_lpSocketHandler)))
{
return false;
}
}
return true;
}
// Desc : Listener를 생성한다.
bool CIOCPNet::AddListener(CSessionPolicy* lpSessionPolicy,
const char* lpListenAddress, unsigned short usPort,
unsigned long dwMaxListenPeding,
CValidateConnection* lpValidateConnection)
{
if(0 == lpSessionPolicy || !lpSessionPolicy->IsValid() ||
0 == m_lpSocketHandler || 0 == m_lpSessionMgr)
{
return false;
}
CListener* lpListener = new (std::nothrow) CListener(*m_lpSocketHandler,
*lpSessionPolicy, *m_lpSessionMgr, lpValidateConnection);
if(0 == lpListener)
{
return false;
}
if(!lpListener->Initialize(lpListenAddress, usPort, dwMaxListenPeding))
{
delete lpListener;
return false;
}
lpSessionPolicy->AddRef();
SessionLock::Syncronize sync(m_IOCPLock);
m_ListenerList.push_back(lpListener);
++m_SessionPolicyMap[lpSessionPolicy];
return true;
}
// Desc : 연결 세션을 생성한다.
bool CIOCPNet::Connect(CSessionPolicy* lpSessionPolicy,
const char* lpConnectAddress, unsigned short usPort)
{
if(0 == lpSessionPolicy || !lpSessionPolicy->IsValid() ||
0 == m_lpSocketHandler || 0 == m_lpSessionMgr)
{
return false;
}
SOCKET hConnectedSocket = lpSessionPolicy->GetSocketFactory().CreateConnectedSocket(lpConnectAddress, usPort);
if(INVALID_SOCKET == hConnectedSocket)
{
ERRLOG3(g_Log, "Connected socket creation error : %d, destination : %s:%d",
WSAGetLastError(), lpConnectAddress, usPort);
}
else
{
CSession* lpSession = m_lpSessionMgr->CreateSession(*lpSessionPolicy);
if(0 != lpSession)
{
if(m_lpSocketHandler->AttachToHander(
reinterpret_cast<HANDLE>(hConnectedSocket),
reinterpret_cast<ULONG_PTR>(lpSession)))
{
lpSession->Socket(hConnectedSocket);
lpSession->SetAddress(INET_Addr(lpConnectAddress, usPort), INET_Addr());
DETLOG3(g_SessionLog, "SP:0x%p/DP:0x%p/IP:%15s/ Connect Success.",
lpSession, lpSession->GetDispatch(), lpConnectAddress);
lpSession->InternalRecv();
m_lpSessionMgr->Add(lpSession);
lpSessionPolicy->AddRef();
SessionLock::Syncronize sync(m_IOCPLock);
++m_SessionPolicyMap[lpSessionPolicy];
return true;
}
m_lpSessionMgr->DeleteSession(lpSession);
}
closesocket(hConnectedSocket);
}
return false;
}
// Desc : Listener에 딸린 세션들과, ConnectedSession의 처리를 한다.
void CIOCPNet::Process()
{
if(0 != m_lpSessionMgr)
{
m_lpSessionMgr->Process();
}
}
// Desc : 모든 Listener와 세션을 종료한다.
bool CIOCPNet::Destroy()
{
m_IOCPLock.Lock();
if(!(m_dwFlags & DESTROYED_IOCP))
{
CThreadMgr* lpThreadMgr = 0;
CCompletionHandler* lpSocketHandler = 0;
CSessionMgr* lpSessionMgr = 0;
SessionPolicyMap tempMap(m_SessionPolicyMap);
m_SessionPolicyMap.clear();
std::swap(m_lpThreadMgr, lpThreadMgr);
std::swap(m_lpSocketHandler, lpSocketHandler);
std::swap(m_lpSessionMgr, lpSessionMgr);
m_dwFlags |= DESTROYED_IOCP;
m_IOCPLock.Unlock();
DestroyListener();
delete lpSessionMgr;
delete lpThreadMgr;
delete lpSocketHandler;
SessionPolicyMap::iterator pos = tempMap.begin();
SessionPolicyMap::iterator end = tempMap.end();
for(; pos != end; ++pos)
{
for(unsigned int nReleaseCount = pos->second;
0 != nReleaseCount; --nReleaseCount)
{
pos->first->Release();
}
}
return true;
}
m_IOCPLock.Unlock();
return false;
}
void CIOCPNet::DestroyListener()
{
ListenerList deleteList;
{
SessionLock::Syncronize sync(m_IOCPLock);
deleteList.splice(deleteList.end(), m_ListenerList);
}
ListenerList::iterator pos = deleteList.begin();
ListenerList::iterator end = deleteList.end();
for(; pos != end; ++pos)
{
delete (*pos);
}
}
// Desc : 현재 Accept를 pending하고 있는 세션의 수를 리턴.
unsigned long CIOCPNet::GetAcceptPendingNum()
{
unsigned long dwPendingNum = 0;
SessionLock::Syncronize sync(m_IOCPLock);
for(ListenerList::iterator itr = m_ListenerList.begin();
itr != m_ListenerList.end(); ++itr)
{
dwPendingNum += (*itr)->GetPendingAcceptNum();
}
return dwPendingNum;
}
unsigned long CIOCPNet::GetSessionNum()
{
if(0 != m_lpSessionMgr)
{
return m_lpSessionMgr->GetSessionNum();
}
return 0;
}
/*
void CIOCPNet::LogListeners()
{
SessionLock::Syncronize sync(m_IOCPLock);
std::for_each(m_ListenerList.begin(), m_ListenerList.end(),
std::mem_fun(CListener::LogListenerStatus));
}
void CIOCPNet::LogConnected()
{
using namespace std;
unsigned int nStateNum[CSession::MAX_SESSION_STATE];
std::fill_n(nStateNum, unsigned int(CSession::MAX_SESSION_STATE), 0);
const char* szDelimiter = "// ------------------------------------------------------------------------------- ";
char szProgramName[MAX_PATH];
char szFileName[MAX_PATH];
char szTime[MAX_PATH];
SYSTEMTIME systemTime;
GetLocalTime(&systemTime);
DbgUtils::SetProgramName(szProgramName, MAX_PATH);
_snprintf(szTime, MAX_PATH, "%04d%02d%02d-%02d%02d%02d",
systemTime.wYear, systemTime.wMonth, systemTime.wDay,
systemTime.wHour, systemTime.wMinute, systemTime.wSecond);
_snprintf(szFileName, MAX_PATH, "%s/ConnectedLog-%s.txt", szProgramName, szTime);
fstream logfile(szFileName, ios::out | ios::app);
fstream::char_type endline = logfile.widen('\n');
logfile << szDelimiter << endline;
m_IOCPLock.Lock();
unsigned int nConnectedNum = 0;
ConnectedArray::iterator first = m_ConnectedArray.begin();
ConnectedArray::iterator last = m_ConnectedArray.end();
for(; first != last; ++first)
{
logfile << **first << endline;
++nStateNum[(*first)->m_cCurrentStatus];
++nConnectedNum;
}
m_IOCPLock.Unlock();
logfile << endline << szDelimiter << endline
<< "Time : " << szTime << endline << endline
<< "nUNINITIALIZED : " << nStateNum[CSession::UNINITIALIZED] << endline
<< "ACCEPT_PENDING : " << nStateNum[CSession::ACCEPT_PENDING] << endline
<< "CONNECTED : " << nStateNum[CSession::CONNECTED] << endline
<< "DISCONNECTED : " << nStateNum[CSession::DISCONNECTED] << endline
<< "Total : " << nConnectedNum << endl;
}
*/