Session에 Recv을 추가
헷갈리니 그냥 처음부터 정리
int main()
{
// ServerService를 만들고
ServerServiceRef service = MakeShared<ServerService>(
NetAddress(L"127.0.0.1", 7777),
MakeShared<IocpCore>(),
MakeShared<GameSession>, // TODO : SessionManager 등
100);
// Start 실행
ASSERT_CRASH(service->Start());
// ...
bool ServerService::Start()
{
if (CanStart() == false)
return false;
// listener 생성하고
_listener = MakeShared<Listener>();
if (_listener == nullptr)
return false;
ServerServiceRef service = static_pointer_cast<ServerService>(shared_from_this());
// listener를 실행
if (_listener->StartAccept(service) == false)
return false;
return true;
}
bool Listener::StartAccept(ServerServiceRef service)
{
_service = service;
if (_service == nullptr)
return false;
// 소켓연결에 관한 부분은 생략
const int32 acceptCount = _service->GetMaxSessionCount();
for (int32 i = 0; i < acceptCount; i++)
{
AcceptEvent* acceptEvent = xnew<AcceptEvent>();
acceptEvent->owner = shared_from_this();
_acceptEvents.push_back(acceptEvent);
// AcceptEvent를 등록
RegisterAccept(acceptEvent);
}
return true;
}
void Listener::RegisterAccept(AcceptEvent* acceptEvent)
{
SessionRef session = _service->CreateSession(); // Register IOCP
acceptEvent->Init();
acceptEvent->session = session;
DWORD bytesReceived = 0;
// Accept
if (false == SocketUtils::AcceptEx(_socket, session->GetSocket(), session->_recvBuffer, 0, sizeof(SOCKADDR_IN) + 16, sizeof(SOCKADDR_IN) + 16, OUT & bytesReceived, static_cast<LPOVERLAPPED>(acceptEvent)))
{
const int32 errorCode = ::WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
// 일단 다시 Accept 걸어준다
RegisterAccept(acceptEvent);
}
}
}
void Listener::Dispatch(IocpEvent* iocpEvent, int32 numOfBytes)
{
ASSERT_CRASH(iocpEvent->eventType == EventType::Accept);
AcceptEvent* acceptEvent = static_cast<AcceptEvent*>(iocpEvent);
ProcessAccept(acceptEvent);
}
void Listener::ProcessAccept(AcceptEvent* acceptEvent)
{
SessionRef session = acceptEvent->session;
// ...
session->SetNetAddress(NetAddress(sockAddress));
// session의 ProcessConnect() 실행
session->ProcessConnect();
RegisterAccept(acceptEvent);
}
void Session::ProcessConnect()
{
_connected.store(true);
// 세션 등록
GetService()->AddSession(GetSessionRef());
// 컨텐츠 코드에서 오버로딩
OnConnected();
// 수신 등록
RegisterRecv();
}
void Session::RegisterRecv()
{
if (IsConnected() == false)
return;
_recvEvent.Init();
_recvEvent.owner = shared_from_this(); // ADD_REF
WSABUF wsaBuf;
wsaBuf.buf = reinterpret_cast<char*>(_recvBuffer);
wsaBuf.len = len32(_recvBuffer);
DWORD numOfBytes = 0;
DWORD flags = 0;
if (SOCKET_ERROR == ::WSARecv(_socket, &wsaBuf, 1, OUT &numOfBytes, OUT &flags, &_recvEvent, nullptr))
{
int32 errorCode = ::WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
HandleError(errorCode);
_recvEvent.owner = nullptr; // RELEASE_REF
}
}
}
void Session::Dispatch(IocpEvent* iocpEvent, int32 numOfBytes)
{
switch (iocpEvent->eventType)
{
case EventType::Connect:
ProcessConnect();
break;
case EventType::Recv:
ProcessRecv(numOfBytes);
break;
case EventType::Send:
ProcessSend(numOfBytes);
break;
default:
break;
}
}
전체코드
#pragma once
#include "IocpCore.h"
#include "IocpEvent.h"
#include "NetAddress.h"
class Service;
/*--------------
Session
---------------*/
class Session : public IocpObject
{
friend class Listener;
friend class IocpCore;
friend class Service;
public:
Session();
virtual ~Session();
public:
void Disconnect(const WCHAR* cause);
shared_ptr<Service> GetService() { return _service.lock(); }
void SetService(shared_ptr<Service> service) { _service = service; }
public:
/* 정보 관련 */
void SetNetAddress(NetAddress address) { _netAddress = address; }
NetAddress GetAddress() { return _netAddress; }
SOCKET GetSocket() { return _socket; }
bool IsConnected() { return _connected; }
SessionRef GetSessionRef() { return static_pointer_cast<Session>(shared_from_this()); }
private:
/* 인터페이스 구현 */
virtual HANDLE GetHandle() override;
virtual void Dispatch(class IocpEvent* iocpEvent, int32 numOfBytes = 0) override;
private:
/* 전송 관련 */
void RegisterConnect();
void RegisterRecv();
void RegisterSend();
void ProcessConnect();
void ProcessRecv(int32 numOfBytes);
void ProcessSend(int32 numOfBytes);
void HandleError(int32 errorCode);
protected:
/* 컨텐츠 코드에서 오버로딩 */
virtual void OnConnected() { }
virtual int32 OnRecv(BYTE* buffer, int32 len) { return len; }
virtual void OnSend(int32 len) { }
virtual void OnDisconnected() { }
public:
// TEMP
char _recvBuffer[1000];
private:
weak_ptr<Service> _service;
SOCKET _socket = INVALID_SOCKET;
NetAddress _netAddress = {};
Atomic<bool> _connected = false;
private:
USE_LOCK;
/* 수신 관련 */
/* 송신 관련 */
private:
/* IocpEvent 재사용 */
RecvEvent _recvEvent;
};
#include "pch.h"
#include "Session.h"
#include "SocketUtils.h"
#include "Service.h"
/*--------------
Session
---------------*/
Session::Session()
{
_socket = SocketUtils::CreateSocket();
}
Session::~Session()
{
SocketUtils::Close(_socket);
}
void Session::Disconnect(const WCHAR* cause)
{
if (_connected.exchange(false) == false)
return;
// TEMP
wcout << "Disconnect : " << cause << endl;
OnDisconnected(); // 컨텐츠 코드에서 오버로딩
SocketUtils::Close(_socket);
GetService()->ReleaseSession(GetSessionRef());
}
HANDLE Session::GetHandle()
{
return reinterpret_cast<HANDLE>(_socket);
}
void Session::Dispatch(IocpEvent* iocpEvent, int32 numOfBytes)
{
switch (iocpEvent->eventType)
{
case EventType::Connect:
ProcessConnect();
break;
case EventType::Recv:
ProcessRecv(numOfBytes);
break;
case EventType::Send:
ProcessSend(numOfBytes);
break;
default:
break;
}
}
void Session::RegisterConnect()
{
}
void Session::RegisterRecv()
{
if (IsConnected() == false)
return;
_recvEvent.Init();
_recvEvent.owner = shared_from_this(); // ADD_REF
WSABUF wsaBuf;
wsaBuf.buf = reinterpret_cast<char*>(_recvBuffer);
wsaBuf.len = len32(_recvBuffer);
DWORD numOfBytes = 0;
DWORD flags = 0;
if (SOCKET_ERROR == ::WSARecv(_socket, &wsaBuf, 1, OUT &numOfBytes, OUT &flags, &_recvEvent, nullptr))
{
int32 errorCode = ::WSAGetLastError();
if (errorCode != WSA_IO_PENDING)
{
HandleError(errorCode);
_recvEvent.owner = nullptr; // RELEASE_REF
}
}
}
void Session::RegisterSend()
{
}
void Session::ProcessConnect()
{
_connected.store(true);
// 세션 등록
GetService()->AddSession(GetSessionRef());
// 컨텐츠 코드에서 오버로딩
OnConnected();
// 수신 등록
RegisterRecv();
}
void Session::ProcessRecv(int32 numOfBytes)
{
_recvEvent.owner = nullptr; // RELEASE_REF
if (numOfBytes == 0)
{
Disconnect(L"Recv 0");
return;
}
// TODO
cout << "Recv Data Len = " << numOfBytes << endl;
// 수신 등록
RegisterRecv();
}
void Session::ProcessSend(int32 numOfBytes)
{
}
void Session::HandleError(int32 errorCode)
{
switch (errorCode)
{
case WSAECONNRESET:
case WSAECONNABORTED:
Disconnect(L"HandleError");
break;
default:
// TODO : Log
cout << "Handle Error : " << errorCode << endl;
break;
}
}