DragonNest/Server/ServiceMonitorEx/Source/EventSelectTcpClient.inl
2024-12-19 09:48:26 +08:00

710 lines
25 KiB
C++

///////////////////////////////////////////////////////////////////
// INCLUDE
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// IMPLEMENTATION
///////////////////////////////////////////////////////////////////
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::CEventSelectTcpClient
//*---------------------------------------------------------------
// DESC : 생성자
// PARM : N/A
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
CEventSelectTcpClient<TSESSION>::CEventSelectTcpClient()
{
Initialize();
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::~CEventSelectTcpClient
//*---------------------------------------------------------------
// DESC : 소멸자
// PARM : N/A
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
CEventSelectTcpClient<TSESSION>::~CEventSelectTcpClient()
{
Finalize();
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::Initialize
//*---------------------------------------------------------------
// DESC : 객체 관련 자원들을 초기화
// PARM : N/A
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::Initialize()
{
m_lpfnErrorNotifyProc = NULL;
m_lpErrorNotifyProcParam = NULL;
m_hEventEndThread = NULL;
m_hEventAddHandle = NULL;
if (NOERROR != m_crEventSelectTcpClient.Open()) {
BASE_RETURN(FALSE);
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::Finalize
//*---------------------------------------------------------------
// DESC : 객체 관련 자원들을 해제
// PARM : N/A
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
VOID CEventSelectTcpClient<TSESSION>::Finalize()
{
End();
m_crEventSelectTcpClient.Close();
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::Start
//*---------------------------------------------------------------
// DESC : 객체의 기본 데이터를 세팅하고 사용가능한 상태로 세팅
// PARM : 1 . uStackSize - 스레드 스택크기 (기본값 0 → 1MB)
// 2 . m_lpPrepProc - 스레드 시작 시 실행되는 루틴 (기본값 NULL)
// 3 . m_lpPostProc - 스레드 종료 시 실행되는 루틴 (기본값 NULL)
// 4 . m_lpPrepProcParam - 스레드 시작 루틴에 전달되는 인자 (기본값 NULL)
// 5 . m_lpPostProcParam - 스레드 종료 루틴에 전달되는 인자 (기본값 NULL)
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::Start(
UINT uStackSize,
CThread::LPFN_PREP_PROC lpfnPrepProc,
CThread::LPFN_POST_PROC lpfnPostProc,
LPVOID lpPrepProcParam,
LPVOID lpPostProcParam
)
{
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
if (m_hEventEndThread != NULL ||
m_hEventAddHandle != NULL ||
m_EventSelectMainWorkerThread.GetHandle()) {
// 이미 Start() 되었음 ? → End() 이후 사용가능
SaveErrorMessage(0, _T("m_EventSelectMainWorkerThread.GetHandle() - CEventSelectTcpClient::Start()"));
BASE_RETURN(FALSE);
}
BOOL bRetVal = m_EventSelectMainWorkerThread.Start(
MainWorkerThreadProc, this, CVarArg<64>(_T("EVTC-MAIN")),
uStackSize, FALSE, FALSE,
lpfnPrepProc,
lpfnPostProc,
lpPrepProcParam,
lpPostProcParam
);
if (!bRetVal) {
BASE_RETURN(FALSE);
}
bRetVal = m_EventSelectMainWorkerThread.SetPriority(THREAD_PRIORITY_NORMAL+2);
if (!bRetVal) {
BASE_RETURN(FALSE);
}
m_hEventEndThread = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hEventEndThread) {
SaveErrorMessage(::GetLastError(), _T(" - CEventSelectTcpClient::Start()"));
BASE_RETURN(FALSE);
}
m_hEventAddHandle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hEventAddHandle) {
SaveErrorMessage(::GetLastError(), _T(" - CEventSelectTcpClient::Start()"));
BASE_RETURN(FALSE);
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::End
//*---------------------------------------------------------------
// DESC : 객체의 기본 데이터를 해제하고 초기화
// PARM : N/A
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
VOID CEventSelectTcpClient<TSESSION>::End()
{
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
if (m_EventSelectMainWorkerThread.GetHandle()) {
// 작업 스레드를 종료시킴
::SetEvent(m_hEventEndThread);
::WaitForSingleObject(m_EventSelectMainWorkerThread.GetHandle(), INFINITE);
m_EventSelectMainWorkerThread .End();
}
if (m_hEventEndThread) {
::CloseHandle(m_hEventEndThread);
m_hEventEndThread = NULL;
}
if (m_hEventAddHandle) {
::CloseHandle(m_hEventAddHandle);
m_hEventAddHandle = NULL;
}
std::vector<CEventSelectTcpClientSession<TSESSION>*>::iterator it = m_vtEventSelectTcpClientSession.begin();
for (; it != m_vtEventSelectTcpClientSession.end() ; ++it) {
if ((*it)) {
(*it)->Reset();
(*it)->DeleteBuffer();
m_SessionMemoryPool.ReleaseMemory(static_cast<TSESSION*>(*it));
}
}
m_vtEventSelectTcpClientSession.clear();
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::GetSession
//*---------------------------------------------------------------
// DESC : 사용 가능한 세션객체를 얻음
// PARM : 1 . lpfnBaseNotifyProc - 기본 이벤트 (연결, 종료, 에러) 를 통보받을 함수 포인터
// 2 . lpfnRecvNotifyProc - 수신 이벤트를 통보받을 함수 포인터
// 3 . lpBaseNotifyProcParam - 기본 이벤트 사용자 파라메터
// 4 . lpRecvNotifyProcParam - 수신 이벤트 사용자 파라메터
// 5 . iRecvAppBufferSize - 세션의 수신버퍼 크기 (응용)
// 6 . iSendAppBufferSize - 세션의 송신버퍼 크기 (응용)
// 7 . iRecvSckBufferSize - 세션의 수신버퍼 크기 (소켓)
// 8 . iSendSckBufferSize - 세션의 송신버퍼 크기 (소켓)
// RETV : 세션 객체 포인터
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
TSESSION* CEventSelectTcpClient<TSESSION>::GetSession(
LPFN_BASE_NOTIFY_PROC lpfnBaseNotifyProc,
LPFN_RECV_NOTIFY_PROC lpfnRecvNotifyProc,
LPVOID lpBaseNotifyProcParam,
LPVOID lpRecvNotifyProcParam,
INT iRecvAppBufferSize,
INT iSendAppBufferSize,
INT iRecvSckBufferSize,
INT iSendSckBufferSize
)
{
if (!lpfnBaseNotifyProc || !lpfnRecvNotifyProc) {
// 에러
SaveErrorMessage(0, _T("!lpfnBaseNotifyProc || !lpfnRecvNotifyProc - CEventSelectTcpClient::GetSession()"));
return NULL;
}
if (iRecvAppBufferSize <= 0 || iSendAppBufferSize <= 0) {
// 에러
SaveErrorMessage(0, _T("iRecvAppBufferSize <= 0 || iSendAppBufferSize <= 0 - CEventSelectTcpClient::GetSession()"));
return NULL;
}
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
TSESSION* lpEventSelectTcpClientSession = m_SessionMemoryPool.GetMemory();
if (!lpEventSelectTcpClientSession) {
// 에러
SaveErrorMessage(0, _T("!lpEventSelectTcpClientSession - CEventSelectTcpClient::GetSession()"));
BASE_RETURN(NULL);
}
CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession2 = static_cast<CEventSelectTcpClientSession<TSESSION>*>(lpEventSelectTcpClientSession);
// 아직 사용자에게 전달되지 않은 상태이므로 세션 동기화 필요없음
lpEventSelectTcpClientSession2->SetIsActivated(TRUE);
lpEventSelectTcpClientSession2->Reset();
lpEventSelectTcpClientSession2->SetEventSelectTcpClientPtr(this);
lpEventSelectTcpClientSession2->SetBaseNotifyProc(lpfnBaseNotifyProc, lpBaseNotifyProcParam);
lpEventSelectTcpClientSession2->SetRecvNotifyProc(lpfnRecvNotifyProc, lpRecvNotifyProcParam);
lpEventSelectTcpClientSession2->SetSckBufferSize(iRecvSckBufferSize, iSendSckBufferSize);
if (lpEventSelectTcpClientSession2->CreateBuffer(iRecvAppBufferSize, iSendAppBufferSize) == FALSE) {
// 에러
SaveErrorMessage(0, _T("lpEventSelectTcpClientSession2->CreateBuffer() == FALSE - CEventSelectTcpClient::GetSession()"));
BASE_RETURN(NULL);
}
return lpEventSelectTcpClientSession;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::ReleaseSession
//*---------------------------------------------------------------
// DESC : 사용이 끝난 세션객체를 반환
// PARM : 1 . lpEventSelectTcpClientSession - 세션 객체 포인터
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
VOID CEventSelectTcpClient<TSESSION>::ReleaseSession(TSESSION* lpEventSelectTcpClientSession)
{
if (!lpEventSelectTcpClientSession) {
SaveErrorMessage(0, _T("!lpEventSelectTcpClientSession - CEventSelectTcpClient::ReleaseSession()"));
return;
}
CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession2 = static_cast<CEventSelectTcpClientSession<TSESSION>*>(lpEventSelectTcpClientSession);
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
// 세션 보호 → 이 함수를 호출하는 쪽에서 이루어짐 (필요할 경우에만) - 대부분 TSESSION::Disconnect() 이후에 반환하므로 큰 필요는 없을듯
if (lpEventSelectTcpClientSession2->GetIsActivated() == FALSE) {
// 에러
SaveErrorMessage(0, _T("lpEventSelectTcpClientSession2->GetIsActivated() == FALSE - CEventSelectTcpClient::ReleaseSession()"));
return;
}
lpEventSelectTcpClientSession2->SetIsActivated(FALSE);
lpEventSelectTcpClientSession2->Reset();
lpEventSelectTcpClientSession2->DeleteBuffer();
m_SessionMemoryPool.ReleaseMemory(lpEventSelectTcpClientSession);
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::RegisterSession
//*---------------------------------------------------------------
// DESC : 연결 후 소켓이벤트를 받을 수 있도록 세션객체를 관리자 객체에 등록 (자동으로 수행됨)
// PARM : 1 . lpEventSelectTcpClientSession - 세션 객체 포인터
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::RegisterSession(CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession)
{
// 세션 보호 → 이 함수를 호출하는 쪽에서 이루어짐
if (!lpEventSelectTcpClientSession) {
SaveErrorMessage(0, _T("!lpEventSelectTcpClientSession - CEventSelectTcpClient::RegisterSession()"));
return FALSE;
}
if (lpEventSelectTcpClientSession->GetEventHandle() == NULL) {
SaveErrorMessage(0, _T("lpEventSelectTcpClientSession->GetEventHandle() == NULL - CEventSelectTcpClient::RegisterSession()"));
return FALSE;
}
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
// 세션의 핸들과 포인터를 관리용 벡터에 등록한다.
std::vector<CEventSelectTcpClientSession<TSESSION>*>::iterator it = std::find(m_vtEventSelectTcpClientSession.begin(), m_vtEventSelectTcpClientSession.end(), lpEventSelectTcpClientSession);
if (it == m_vtEventSelectTcpClientSession.end()) {
m_vtEventSelectTcpClientSession.push_back(lpEventSelectTcpClientSession);
}
else {
// 에러 - 핸들이 존재할 수 없다. 혹시라도 이런 경우가 발생하는지 체크해 보아야 한다.
SaveErrorMessage(0, _T("it != m_vtEventSelectTcpClientSession.end() - CEventSelectTcpClient::RegisterSession()"));
}
// 작업 스레드에 핸들이 추가되었다는 이벤트를 보낸다.
if (m_hEventAddHandle) {
::SetEvent(m_hEventAddHandle);
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::UnregisterSession
//*---------------------------------------------------------------
// DESC : 종료 후 소켓이벤트를 받지 않도록 세션객체를 관리자 객체에서 등록해제 (자동으로 수행됨)
// PARM : 1 . lpEventSelectTcpClientSession - 세션 객체 포인터
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::UnregisterSession(CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession)
{
// 세션 보호 → 이 함수를 호출하는 쪽에서 이루어짐
if (!lpEventSelectTcpClientSession) {
SaveErrorMessage(0, _T("!lpEventSelectTcpClientSession - CEventSelectTcpClient::UnregisterSession()"));
return FALSE;
}
if (lpEventSelectTcpClientSession->GetEventHandle() == NULL) {
SaveErrorMessage(0, _T("lpEventSelectTcpClientSession->GetEventHandle() == NULL - CEventSelectTcpClient::UnregisterSession()"));
return FALSE;
}
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
// 벡터에서 세션에 연결된 이벤트 핸들을 찾아서 제거한다.
std::vector<CEventSelectTcpClientSession<TSESSION>*>::iterator it = std::find(m_vtEventSelectTcpClientSession.begin(), m_vtEventSelectTcpClientSession.end(), lpEventSelectTcpClientSession);
if (it != m_vtEventSelectTcpClientSession.end()) {
m_vtEventSelectTcpClientSession.erase(it);
}
else {
// 에러 - 핸들이 존재해야 한다. 혹시라도 이런 경우가 발생하는지 체크해 보아야 한다.
SaveErrorMessage(0, _T("it == m_vtEventSelectTcpClientSession.end() - CEventSelectTcpClient::UnregisterSession()"));
}
// 작업 스레드에 핸들이 제거되었다는 이벤트를 보낸다.
if (m_hEventAddHandle) {
::SetEvent(m_hEventAddHandle);
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::IoEventRecv
//*---------------------------------------------------------------
// DESC : 특정 세션으로 통보된 수신 이벤트를 처리
// PARM : 1 . lpEventSelectTcpClientSession - 세션 객체 포인터
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::IoEventRecv(CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession)
{
// RECV 버퍼에 데이터를 받아서 사용자에게 통보한다.
// 세션 동기화 → RECV 이벤트가 발생하는 스레드가 하나이므로 소켓 보호를 위해 WSARecv() 부분만 동기화
// CLockAuto AutoLock(lpEventSelectTcpClientSession->GetCriticalSection());
if (lpEventSelectTcpClientSession->RecvData() == FALSE) {
// 에러 - SendLeftData() 내부에서 종료처리 하였음
return FALSE;
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::IoEventSend
//*---------------------------------------------------------------
// DESC : 특정 세션으로 통보된 송신종료 이벤트를 처리
// PARM : 1 . lpEventSelectTcpClientSession - 세션 객체 포인터
// RETV : TRUE - 성공 / FALSE - 실패
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
BOOL CEventSelectTcpClient<TSESSION>::IoEventSend(CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSession)
{
// 만약 이전에 보내지 못한 데이 터가 있으면 보낸다.
// 세션 동기화
CLockAuto AutoLock(lpEventSelectTcpClientSession->GetLock());
if (lpEventSelectTcpClientSession->SendLeftData() == SOCKET_ERROR) {
// 에러 - SendLeftData() 내부에서 종료처리 하였음
return FALSE;
}
return TRUE;
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::SetEventArray
//*---------------------------------------------------------------
// DESC : 이벤트 배열을 갱신
// PARM : 1 . lphEventArray - 이벤트 핸들
// 2 . lpEventSelectTcpClientSessionArray - 이벤트 배열 포인터
// 3 . iEventCount - 등록된 이벤트 개수
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
VOID CEventSelectTcpClient<TSESSION>::SetEventArray(LPHANDLE lphEventArray, CEventSelectTcpClientSession<TSESSION>** lpEventSelectTcpClientSessionArray, INT& iEventCount)
{
// 모듈 전체 동기화
CLockAuto AutoLock(&m_crEventSelectTcpClient);
if (!lphEventArray || !lpEventSelectTcpClientSessionArray) {
return;
}
lphEventArray[0] = m_hEventEndThread;
lphEventArray[1] = m_hEventAddHandle;
lpEventSelectTcpClientSessionArray[0] = NULL;
lpEventSelectTcpClientSessionArray[1] = NULL;
iEventCount = DF_ETCL_BASE_EVENT_COUNT;
if (m_vtEventSelectTcpClientSession.empty()) {
// 빈번하게 발생
// BASE_TRACE(_T("m_vtEventSelectTcpClientSession.empty() - CEventSelectTcpClient::SetEventArray()"));
return;
}
iEventCount += (INT)m_vtEventSelectTcpClientSession.size();
if (iEventCount >= WSA_MAXIMUM_WAIT_EVENTS) {
// 이런 경우가 발생하는지 체크해 보아야 한다.
iEventCount = WSA_MAXIMUM_WAIT_EVENTS;
BASE_TRACE(_T("iEventCount >= WSA_MAXIMUM_WAIT_EVENTS - CEventSelectTcpClient::SetEventArray()"));
}
for (INT iIndex = DF_ETCL_BASE_EVENT_COUNT; iIndex < iEventCount ; ++iIndex) {
lphEventArray[iIndex] = m_vtEventSelectTcpClientSession[iIndex-DF_ETCL_BASE_EVENT_COUNT]->GetEventHandle();
lpEventSelectTcpClientSessionArray[iIndex] = m_vtEventSelectTcpClientSession[iIndex-DF_ETCL_BASE_EVENT_COUNT];
if (lphEventArray[iIndex] == NULL) {
// 에러 - 이런 경우가 생기는지 확인해 보아야 한다.
BASE_TRACE(_T("lphEventArray[%d] == NULL - CEventSelectTcpClient::SetEventArray()"), iIndex);
std::vector<CEventSelectTcpClientSession<TSESSION>*>::iterator it = m_vtEventSelectTcpClientSession.begin() + iIndex - DF_ETCL_BASE_EVENT_COUNT;
m_vtEventSelectTcpClientSession.erase(it);
--iIndex;
--iEventCount;
}
}
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::SaveErrorMessage
//*---------------------------------------------------------------
// DESC : 클래스 내부에 에러메시지를 저장, 사용자에게 알려줌
// PARM : 1 . iErrorCode - 시스템 에러코드
// 2 . lpszErrorMessage - 추가적인 에러메시지
// RETV : N/A
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
VOID CEventSelectTcpClient<TSESSION>::SaveErrorMessage(INT iErrorCode, LPCTSTR lpszErrorMessage)
{
if (m_lpfnErrorNotifyProc) {
m_lpfnErrorNotifyProc(this, iErrorCode, m_ErrorFormat.Write(iErrorCode, lpszErrorMessage), m_lpErrorNotifyProcParam);
}
}
//*---------------------------------------------------------------
// TYPE : FUNCTION
// NAME : CEventSelectTcpClient::MainWorkerThreadProc
//*---------------------------------------------------------------
// DESC : 이벤트 처리를 진행할 메인 작업 스레드 프로시저
// PARM : 1 . lpParam - 관리자 객체의 포인터
// RETV : 스레드 종료코드 (0:OK)
// PRGM : B4nFter
//*---------------------------------------------------------------
template<class TSESSION>
UINT __stdcall CEventSelectTcpClient<TSESSION>::MainWorkerThreadProc(LPVOID lpParam)
{
CEventSelectTcpClient* lpEventSelectTcpClient = (CEventSelectTcpClient*) lpParam;
if (lpEventSelectTcpClient == NULL) {
return 0;
}
HANDLE hEventArray[WSA_MAXIMUM_WAIT_EVENTS];
CEventSelectTcpClientSession<TSESSION>* lpEventSelectTcpClientSessionArray[WSA_MAXIMUM_WAIT_EVENTS];
WSANETWORKEVENTS stWsaNetworkEvents;
INT iEventCount;
INT iEventIndex;
INT iRetVal;
INT iErrNo;
BOOL bEndThread = FALSE;
// 이벤트배열을 세팅한다.
lpEventSelectTcpClient->SetEventArray(hEventArray, lpEventSelectTcpClientSessionArray, iEventCount);
while(!bEndThread) {
iRetVal = ::WSAWaitForMultipleEvents(
iEventCount,
hEventArray,
FALSE,
WSA_INFINITE,
FALSE
);
if (iRetVal == WSA_WAIT_FAILED) {
iRetVal = ::WSAGetLastError();
switch(iRetVal) {
case ERROR_INVALID_HANDLE : // 잘못된 핸들이 섞여있었다면 여기서 핸들테이블을 다시 세팅한다.
lpEventSelectTcpClient->SetEventArray(hEventArray, lpEventSelectTcpClientSessionArray, iEventCount);
continue;
default :
continue;
}
}
iEventIndex = iRetVal - WSA_WAIT_EVENT_0;
if (iEventIndex >= WSA_MAXIMUM_WAIT_EVENTS) {
// 에러
continue;
}
switch(iEventIndex) {
case DF_ETCL_EVENT_END_THREAD: // 작업스레드 종료
bEndThread = TRUE;
continue;
case DF_ETCL_EVENT_ADD_HANDLE: // 이벤트핸들 배열 추가/삭제 로 인한 변경
lpEventSelectTcpClient->SetEventArray(hEventArray, lpEventSelectTcpClientSessionArray, iEventCount);
continue;
}
// 일반적인 소켓 이벤트 임
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetSocket() == INVALID_SOCKET) {
continue;
}
iErrNo = ::WSAEnumNetworkEvents(
lpEventSelectTcpClientSessionArray[iEventIndex]->GetSocket(),
hEventArray[iEventIndex],
&stWsaNetworkEvents
);
if (iErrNo == SOCKET_ERROR) {
// 에러
lpEventSelectTcpClient->SaveErrorMessage(::WSAGetLastError(), _T("WSAEnumNetworkEvents() - CEventSelectTcpClient::MainWorkerThreadProc()"));
continue;
}
if (stWsaNetworkEvents.lNetworkEvents & FD_CONNECT) {
if (stWsaNetworkEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
// 에러
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(
EV_NBN_ERROR,
lpEventSelectTcpClientSessionArray[iEventIndex],
(LPVOID)lpEventSelectTcpClient->m_ErrorFormat.Write(stWsaNetworkEvents.iErrorCode[FD_CONNECT_BIT], _T("stWsaNetworkEvents.iErrorCode[FD_CONNECT_BIT] != 0 - CEventSelectTcpClient::MainWorkerThreadProc()")),
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam()
);
}
// 세션을 종료시키고 제거함
lpEventSelectTcpClientSessionArray[iEventIndex]->Disconnect();
continue;
}
// FD_CONNECT 작업
// 새로운 이벤트를 등록한다.
iErrNo = ::WSAEventSelect(lpEventSelectTcpClientSessionArray[iEventIndex]->GetSocket(),
hEventArray[iEventIndex],
FD_READ | FD_WRITE | FD_CLOSE
);
if (iErrNo == SOCKET_ERROR) {
lpEventSelectTcpClient->SaveErrorMessage(::WSAGetLastError(), _T("WSAEventSelect() - CEventSelectTcpClient::MainWorkerThreadProc()"));
// 세션을 종료시키고 제거함
lpEventSelectTcpClientSessionArray[iEventIndex]->Disconnect();
continue;
}
// 사용자에게 세션이 연결되었다는 것을 알린다.
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(EV_NBN_SESSCNNT, lpEventSelectTcpClientSessionArray[iEventIndex], (LPVOID)NULL, lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam());
}
// 단독 작업이므로 다음으로 넘어감
continue;
}
if (stWsaNetworkEvents.lNetworkEvents & FD_READ) {
if (stWsaNetworkEvents.iErrorCode[FD_READ_BIT] != 0) {
// 에러
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(
EV_NBN_ERROR,
lpEventSelectTcpClientSessionArray[iEventIndex],
(LPVOID)lpEventSelectTcpClient->m_ErrorFormat.Write(stWsaNetworkEvents.iErrorCode[FD_READ_BIT], _T("stWsaNetworkEvents.iErrorCode[FD_READ_BIT] != 0 - CEventSelectTcpClient::MainWorkerThreadProc()")),
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam()
);
}
// 세션을 종료시키고 제거함
lpEventSelectTcpClientSessionArray[iEventIndex]->Disconnect();
continue;
}
// FD_READ 작업
if (lpEventSelectTcpClient->IoEventRecv(lpEventSelectTcpClientSessionArray[iEventIndex]) == FALSE) {
continue;
}
}
if (stWsaNetworkEvents.lNetworkEvents & FD_WRITE) {
if (stWsaNetworkEvents.iErrorCode[FD_WRITE_BIT] != 0) {
// 에러
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(
EV_NBN_ERROR,
lpEventSelectTcpClientSessionArray[iEventIndex],
(LPVOID)lpEventSelectTcpClient->m_ErrorFormat.Write(stWsaNetworkEvents.iErrorCode[FD_WRITE_BIT], _T("stWsaNetworkEvents.iErrorCode[FD_WRITE_BIT] != 0 - CEventSelectTcpClient::MainWorkerThreadProc()")),
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam()
);
}
// 세션을 종료시키고 제거함
lpEventSelectTcpClientSessionArray[iEventIndex]->Disconnect();
continue;
}
// FD_WRITE 작업
if (lpEventSelectTcpClient->IoEventSend(lpEventSelectTcpClientSessionArray[iEventIndex]) == FALSE) {
continue;
}
}
if (stWsaNetworkEvents.lNetworkEvents & FD_CLOSE) {
if (stWsaNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
// 에러
/*
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(
EV_NBN_ERROR,
lpEventSelectTcpClientSessionArray[iEventIndex],
(LPVOID)lpEventSelectTcpClient->m_ErrorFormat.Write(stWsaNetworkEvents.iErrorCode[FD_CLOSE_BIT], _T("stWsaNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0 - CEventSelectTcpClient::MainWorkerThreadProc()")),
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam()
);
}
continue;
*/
}
// 사용자에게 세션이 종료되었다는 것을 알린다.
if (lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()) {
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProc()(
EV_NBN_SESSDCNT,
lpEventSelectTcpClientSessionArray[iEventIndex],
(LPVOID)NULL,
lpEventSelectTcpClientSessionArray[iEventIndex]->GetBaseNotifyProcParam()
);
}
// 세션을 종료시키고 제거함
lpEventSelectTcpClientSessionArray[iEventIndex]->Disconnect();
}
}
return 0;
}